<?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=Asrini27</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=Asrini27"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Asrini27"/>
	<updated>2026-09-16T16:04:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165154</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165154"/>
		<updated>2025-04-23T03:48:38Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the reimplemented ProjectTopic and SignedUpTeam models that the team worked on, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones done in the SignedUpTeam model during Project 4.&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We have improved the method logic in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We have simplified the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We have rewritten the complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. The original find_team_participants method utilized complex nested loops and multiple repetitive queries. Our improved approach takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original find_team_users method contained unclear, hardcoded SQL queries. Our improved approach looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. The original find_user_signup_topics method used complicated raw SQL joins. Our improved approach first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165153</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165153"/>
		<updated>2025-04-23T03:46:30Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: Undo revision 165148 by Asrini27 (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the reimplemented ProjectTopic and SignedUpTeam models that the team worked on, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones done in the SignedUpTeam model during Project 4.&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We have improved the method logic in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We have simplified the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We have rewritten the complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165148</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165148"/>
		<updated>2025-04-23T03:42:45Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the reimplemented ProjectTopic and SignedUpTeam models that the team worked on, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones done in the SignedUpTeam model during Project 4.&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We have improved the method logic in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We have simplified the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We have rewritten the complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. The original find_team_participants method utilized complex nested loops and multiple repetitive queries. Our improved approach takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original find_team_users method contained unclear, hardcoded SQL queries. Our improved approach looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. The original find_user_signup_topics method used complicated raw SQL joins. Our improved approach first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165136</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165136"/>
		<updated>2025-04-23T03:30:58Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the reimplemented ProjectTopic and SignedUpTeam models that the team worked on, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones done in the SignedUpTeam model during Project 4.&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We have improved the method logic in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We have simplified the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We have rewritten the complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165091</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165091"/>
		<updated>2025-04-23T02:59:39Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165041</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165041"/>
		<updated>2025-04-23T02:50:10Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165013</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165013"/>
		<updated>2025-04-23T02:32:47Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165010</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165010"/>
		<updated>2025-04-23T02:32:17Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_project_topic_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_signup_test.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_signup_test.png&amp;diff=165009</id>
		<title>File:E2513 signup test.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_signup_test.png&amp;diff=165009"/>
		<updated>2025-04-23T02:31:27Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_project_topic_test.png&amp;diff=165007</id>
		<title>File:E2513 project topic test.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_project_topic_test.png&amp;diff=165007"/>
		<updated>2025-04-23T02:31:09Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165003</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=165003"/>
		<updated>2025-04-23T02:28:00Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlisted Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#waitlisted_teams' do&lt;br /&gt;
  it 'returns waitlisted teams in order' do&lt;br /&gt;
    teams = 5.times.map { Team.create!(assignment: assignment) }&lt;br /&gt;
    teams.each { |t| project_topic.signup_team(t) }&lt;br /&gt;
    # Ensures waitlisted teams are returned in the order they were added.&lt;br /&gt;
    5.times { project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    waitlisted = project_topic.waitlisted_teams&lt;br /&gt;
    expect(waitlisted.size).to eq(3)&lt;br /&gt;
    expect(waitlisted).to eq(waitlisted.sort_by(&amp;amp;:created_at))&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no waitlisted teams' do&lt;br /&gt;
    # Returns an empty array when no teams are waitlisted.&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*That the method returns waitlisted teams sorted by the order in which they were added (FIFO).&lt;br /&gt;
*It returns an empty array if there are no waitlisted teams.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires topic_name' do&lt;br /&gt;
    # Validates presence of topic_name field.&lt;br /&gt;
    topic = ProjectTopic.new(assignment: assignment, max_choosers: 1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:topic_name]).to include(&amp;quot;can't be blank&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'requires non-negative integer for max_choosers' do&lt;br /&gt;
    # Validates that max_choosers is a non-negative number.&lt;br /&gt;
    topic = ProjectTopic.new(topic_name: &amp;quot;Invalid&amp;quot;, assignment: assignment, max_choosers: -1)&lt;br /&gt;
    expect(topic).not_to be_valid&lt;br /&gt;
    expect(topic.errors[:max_choosers]).to include(&amp;quot;must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*A topic cannot be created without a topic_name, enforcing data integrity.&lt;br /&gt;
*The max_choosers attribute must be zero or positive, preventing invalid topic configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Functional Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'functional checks' do&lt;br /&gt;
  it 'increases confirmed team count on signup' do&lt;br /&gt;
    # Ensures that the count of confirmed teams increases after signup.&lt;br /&gt;
    expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'does not allow more than max_choosers confirmed teams' do&lt;br /&gt;
    # Confirms that additional teams beyond limit go to waitlist.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.confirmed_teams.count).to eq(2)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.count).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'removes team’s other waitlisted entries on confirmed signup' do&lt;br /&gt;
    # Ensures a confirmed team is removed from other topic waitlists.&lt;br /&gt;
    t = Team.create!(assignment: assignment)&lt;br /&gt;
    t1 = ProjectTopic.create!(topic_name: &amp;quot;Alt Topic&amp;quot;, assignment: assignment, max_choosers: 0)&lt;br /&gt;
    t1.signup_team(t)&lt;br /&gt;
    expect(t1.waitlisted_teams).to include(t)&lt;br /&gt;
    project_topic.signup_team(t)&lt;br /&gt;
    expect(t1.reload.waitlisted_teams).not_to include(t)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'get_signed_up_teams includes waitlisted and confirmed teams' do&lt;br /&gt;
    # Validates that all signed-up teams, regardless of status, are returned.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.get_signed_up_teams.map(&amp;amp;:team_id)).to include(t1.id, t2.id)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'slot_available? reflects accurate state after signup and drop' do&lt;br /&gt;
    # Checks dynamic behavior of slot availability after signup and drop.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'signed_up_team records are removed when team is dropped' do&lt;br /&gt;
    # Confirms that dropping a team deletes the associated record.&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'multiple topics maintain independent signups' do&lt;br /&gt;
    # Ensures that signups in one topic do not affect another topic.&lt;br /&gt;
    topic2 = ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    topic2.signup_team(team2)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    expect(topic2.confirmed_teams).to include(team2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'promotes the earliest waitlisted team after dropping a confirmed one' do&lt;br /&gt;
    # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams.first).to eq(t3)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.confirmed_teams).to include(t2, t3)&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to be_empty&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'does not increase available slots after promoting a waitlisted team' do&lt;br /&gt;
    # Verifies that slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
    t1 = Team.create!(assignment: assignment)&lt;br /&gt;
    t2 = Team.create!(assignment: assignment)&lt;br /&gt;
    t3 = Team.create!(assignment: assignment)&lt;br /&gt;
    project_topic.signup_team(t1)&lt;br /&gt;
    project_topic.signup_team(t2)&lt;br /&gt;
    project_topic.signup_team(t3)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
    project_topic.drop_team(t1)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*When a team is confirmed for one topic, it is removed from the waitlists of other topics.&lt;br /&gt;
*The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.&lt;br /&gt;
*Slot availability is updated correctly after teams sign up and after a team drops.&lt;br /&gt;
*Dropping a team from a topic deletes the corresponding signup record.&lt;br /&gt;
*Signing up for one topic does not affect signups for another topic.&lt;br /&gt;
*When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.&lt;br /&gt;
*Slot count remains constant when a waitlisted team is promoted.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieving Participants for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_participants' do&lt;br /&gt;
  it 'returns all users in a given team' do&lt;br /&gt;
    participants = SignedUpTeam.find_team_participants(team.id)&lt;br /&gt;
    expect(participants).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if team does not exist' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(-1)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array when team exists but has no users' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.&lt;br /&gt;
*It returns an empty array if team does not exist or if the team exists but has no users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Identifying Users Associated with a Team&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_team_users' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns users in the team that signed up' do&lt;br /&gt;
    users = SignedUpTeam.find_team_users(team.id)&lt;br /&gt;
    expect(users).to contain_exactly(user1, user2)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if no signed up team found' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(new_team.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil team_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_team_users(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.&lt;br /&gt;
*It returns an empty array if no signed up team is found or if the team_id is a nil value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Retrieve Topic details for Teams&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.find_user_signup_topics' do&lt;br /&gt;
  let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) }&lt;br /&gt;
 &lt;br /&gt;
  it 'returns topics signed up by user’s team' do&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'returns empty array if user has no teams or no signups' do&lt;br /&gt;
    unknown = User.create!(&lt;br /&gt;
      name: &amp;quot;Ghost&amp;quot;,&lt;br /&gt;
      full_name: &amp;quot;Ghost User&amp;quot;,&lt;br /&gt;
      password: &amp;quot;password&amp;quot;,&lt;br /&gt;
      email: &amp;quot;ghost@example.com&amp;quot;,&lt;br /&gt;
      role: student_role&lt;br /&gt;
    )&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles nil user_id gracefully' do&lt;br /&gt;
    expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([])&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  it 'handles user with multiple teams' do&lt;br /&gt;
    team2 = Team.create!(assignment: assignment)&lt;br /&gt;
    team2.users &amp;lt;&amp;lt; user1&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team2)&lt;br /&gt;
    topics = SignedUpTeam.find_user_signup_topics(user1.id)&lt;br /&gt;
    expect(topics).to include(project_topic)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that&lt;br /&gt;
*The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.&lt;br /&gt;
*It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.&lt;br /&gt;
*The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=164803</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=164803"/>
		<updated>2025-04-22T22:54:08Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. This method takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(team_id)&lt;br /&gt;
  team = Team.find_by(id: team_id)&lt;br /&gt;
  return [] unless team&lt;br /&gt;
 &lt;br /&gt;
  team.users.to_a  &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. This method looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(team_id)&lt;br /&gt;
  signed_up_team = SignedUpTeam.find_by(team_id: team_id)&lt;br /&gt;
  return [] unless signed_up_team&lt;br /&gt;
 &lt;br /&gt;
  signed_up_team.team.try(:users).to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. The method first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(user_id)&lt;br /&gt;
  user = User.find_by(id: user_id)&lt;br /&gt;
  return [] unless user&lt;br /&gt;
 &lt;br /&gt;
  ProjectTopic.joins(:signed_up_teams)  &lt;br /&gt;
              .where(signed_up_teams: { team_id: user.teams.pluck(:id) })&lt;br /&gt;
              .distinct.to_a&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163866</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163866"/>
		<updated>2025-04-08T03:57:31Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Purpose:&amp;lt;/b&amp;gt; Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163860</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163860"/>
		<updated>2025-04-08T03:38:20Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The previous implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163857</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163857"/>
		<updated>2025-04-08T03:33:50Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163855</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163855"/>
		<updated>2025-04-08T03:28:51Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163854</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163854"/>
		<updated>2025-04-08T03:26:44Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#We will also check if proper validation and error handling has been implemented throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We will be implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163852</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163852"/>
		<updated>2025-04-08T03:21:58Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#We will also check if proper validation and error handling has been implemented throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We will be implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163851</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163851"/>
		<updated>2025-04-08T03:21:43Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
#User Access and Team Signup:&lt;br /&gt;
#*Users initially access the available project topics.&lt;br /&gt;
#*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
#Slot Availability Check:&lt;br /&gt;
#*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
#*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
#*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
#Identifying Team Participants:&lt;br /&gt;
#*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
#Team Drop and Waitlist Promotion:&lt;br /&gt;
#*Teams can drop topics using the drop_team method.&lt;br /&gt;
#*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
#Enhanced User and Topic Tracking:&lt;br /&gt;
#*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
#*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#We will also check if proper validation and error handling has been implemented throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We will be implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163828</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163828"/>
		<updated>2025-04-08T03:09:02Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
#The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.&lt;br /&gt;
#*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
#*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
1. User Access and Team Signup:&lt;br /&gt;
*Users initially access the available project topics.&lt;br /&gt;
*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
2. Slot Availability Check:&lt;br /&gt;
*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
3. Identifying Team Participants:&lt;br /&gt;
*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
4. Team Drop and Waitlist Promotion:&lt;br /&gt;
*Teams can drop topics using the drop_team method.&lt;br /&gt;
*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
5. Enhanced User and Topic Tracking:&lt;br /&gt;
*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#We will also check if proper validation and error handling has been implemented throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We will be implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163821</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163821"/>
		<updated>2025-04-08T03:04:43Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
This project builds on E2513, and should begin with the refactoring done by that project.&lt;br /&gt;
&lt;br /&gt;
The refactoring done in E2513 consisted of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
The current project focuses on improving clarity, modularity, and maintainability by extensively reimplementing and testing specific methods from the SignedUpTeam model.&lt;br /&gt;
The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability. Specifically:&lt;br /&gt;
&lt;br /&gt;
*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. SignUpTopic Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignUpTeam Model&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. ProjectTopicsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. SignedUpTeamsController&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones to be done in the SignedUpTeam model during Project 4&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
1. User Access and Team Signup:&lt;br /&gt;
*Users initially access the available project topics.&lt;br /&gt;
*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
2. Slot Availability Check:&lt;br /&gt;
*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
3. Identifying Team Participants:&lt;br /&gt;
*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
4. Team Drop and Waitlist Promotion:&lt;br /&gt;
*Teams can drop topics using the drop_team method.&lt;br /&gt;
*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
5. Enhanced User and Topic Tracking:&lt;br /&gt;
*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#We will be improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#We will be simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#We will also be rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#We will also check if proper validation and error handling has been implemented throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We will be implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163792</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=163792"/>
		<updated>2025-04-08T02:52:11Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
This project builds on E2513, and should begin with the refactoring done by that project.&lt;br /&gt;
&lt;br /&gt;
The refactoring done in E2513 consisted of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
The current project focuses on improving clarity, modularity, and maintainability by extensively reimplementing and testing specific methods from the SignedUpTeam model.&lt;br /&gt;
The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability. Specifically:&lt;br /&gt;
&lt;br /&gt;
*find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.&lt;br /&gt;
*find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Previous Implementation of E2513==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
====UML Diagram====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_UML.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The UML diagram showcases the updated ProjectTopic and SignedUpTeam models that the team will reimplement, and lists the reimplemented methods for each mode.&lt;br /&gt;
&lt;br /&gt;
====Flowchart====&lt;br /&gt;
[[File:E2513_OODD_Design_Doc_Flowchart.png|500px]]&lt;br /&gt;
&lt;br /&gt;
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and newly introduced functionalities to be implemented in Project 4 in the ProjectTopic and SignedUpTeam models:&lt;br /&gt;
&lt;br /&gt;
1. User Access and Team Signup:&lt;br /&gt;
*Users initially access the available project topics.&lt;br /&gt;
*Teams then sign up for their preferred topics via the signup_team method.&lt;br /&gt;
2. Slot Availability Check:&lt;br /&gt;
*Upon signup, the system checks if topic slots are available (available_slots).&lt;br /&gt;
*If slots are available, the team is added directly as a confirmed participant.&lt;br /&gt;
*If no slots remain, the team is placed on a waitlist.&lt;br /&gt;
3. Identifying Team Participants:&lt;br /&gt;
*The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.&lt;br /&gt;
4. Team Drop and Waitlist Promotion:&lt;br /&gt;
*Teams can drop topics using the drop_team method.&lt;br /&gt;
*If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.&lt;br /&gt;
5. Enhanced User and Topic Tracking:&lt;br /&gt;
*find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.&lt;br /&gt;
*find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Previous Implementations==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.&lt;br /&gt;
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.&lt;br /&gt;
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.&lt;br /&gt;
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.&lt;br /&gt;
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
#Improving method logic  in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.&lt;br /&gt;
#Simplifing the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.&lt;br /&gt;
#Rewriting complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution&lt;br /&gt;
#Implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Included a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#Implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#Implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Previously, find_team_participants utilized complex nested loops and multiple repetitive queries, significantly degrading readability and query performance. Our improved approach will replace these with a single, efficient ActiveRecord query using direct joins (SignedUpTeam → Team → Users) and SQL aggregation (GROUP_CONCAT). This provides faster database retrieval, clearer logic, and significantly enhanced maintainability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_participants(assignment_id)&lt;br /&gt;
  SignedUpTeam&lt;br /&gt;
    .joins(team: :users, :project_topic)&lt;br /&gt;
    .where(project_topics: { assignment_id: assignment_id })&lt;br /&gt;
    .select(&lt;br /&gt;
      'signed_up_teams.*',&lt;br /&gt;
      'teams.name AS team_name',&lt;br /&gt;
      'GROUP_CONCAT(users.name SEPARATOR &amp;quot;, &amp;quot;) AS participant_names'&lt;br /&gt;
    )&lt;br /&gt;
    .group('signed_up_teams.id, teams.name')&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. The original implementation of find_team_users contained unclear, hardcoded SQL queries, causing difficulty in readability and maintainability. We will simplify this method using ActiveRecord associations, explicitly joining teams with users, directly filtering by assignment and user IDs. This clear logic eliminates redundant operations, enhances query efficiency, and makes future updates straightforward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_team_users(assignment_id, user_id)&lt;br /&gt;
  Team.joins(:users)&lt;br /&gt;
      .where(parent_id: assignment_id, teams_users: { user_id: user_id })&lt;br /&gt;
      .distinct&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. Previously, find_user_signup_topics used complicated raw SQL joins, resulting in difficult-to-follow logic and inefficiencies. Our improved solution will utilize ActiveRecord's association-based querying (SignedUpTeam → ProjectTopic) and explicit attribute selection, streamlining data retrieval. This refactoring significantly improves readability, reduces database overhead, and clearly communicates the intended logic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def self.find_user_signup_topics(assignment_id, team_id)&lt;br /&gt;
  SignedUpTeam.includes(:project_topic)&lt;br /&gt;
              .where(project_topics: { assignment_id: assignment_id }, team_id: team_id)&lt;br /&gt;
              .select(&lt;br /&gt;
                'project_topics.id AS topic_id',&lt;br /&gt;
                'project_topics.topic_name AS topic_name',&lt;br /&gt;
                'signed_up_teams.is_waitlisted',&lt;br /&gt;
                'signed_up_teams.preference_priority_number'&lt;br /&gt;
              )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
====Method Specific Testing Strategy====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;1. find_team_participants&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve participants for teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_participants&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid Assignment ID&lt;br /&gt;
| Query existing assignment with teams&lt;br /&gt;
| Returns participant list with formatted names&lt;br /&gt;
|-&lt;br /&gt;
| Empty Assignment&lt;br /&gt;
| Query assignment with no signups&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Participants&lt;br /&gt;
| Team with 5 members&lt;br /&gt;
| Returns all names in CSV format&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| Team exists in multiple assignments&lt;br /&gt;
| Only shows target assignment participants&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;2. find_team_users&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Identify users associated with teams in a specific assignment&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_team_users&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Valid User/Assignment&lt;br /&gt;
| User participates in target assignment&lt;br /&gt;
| Returns user's teams&lt;br /&gt;
|-&lt;br /&gt;
| Cross-Assignment Filter&lt;br /&gt;
| User has teams in other assignments	&lt;br /&gt;
| Excludes non-target teams&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Teams&lt;br /&gt;
| User belongs to 3 teams in assignment	&lt;br /&gt;
| Returns all 3 team records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid User ID	&lt;br /&gt;
| Query non-existent user ID	&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;3. find_user_signup_topics&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose: Retrieve topic details for a team's signups&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Testing for find_user_signup_topics&lt;br /&gt;
|-&lt;br /&gt;
! Test Scenario&lt;br /&gt;
! Test Description&lt;br /&gt;
! Expected Outcome&lt;br /&gt;
|-&lt;br /&gt;
| Active Signups&lt;br /&gt;
| Team has confirmed/waitlisted topics	&lt;br /&gt;
| Returns both statuses&lt;br /&gt;
|-&lt;br /&gt;
| No Topics Signed	&lt;br /&gt;
| New team with no signups		&lt;br /&gt;
| Empty result set&lt;br /&gt;
|-&lt;br /&gt;
| Multiple Topics	&lt;br /&gt;
| Team signed up for 5 topics		&lt;br /&gt;
| Returns all 5 records&lt;br /&gt;
|-&lt;br /&gt;
| Invalid Team ID		&lt;br /&gt;
| Query non-existent team		&lt;br /&gt;
| Returns empty collection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_OODD_Design_Doc_UML.png&amp;diff=163748</id>
		<title>File:E2513 OODD Design Doc UML.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_OODD_Design_Doc_UML.png&amp;diff=163748"/>
		<updated>2025-04-08T02:34:28Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_OODD_Design_Doc_Flowchart.png&amp;diff=163636</id>
		<title>File:E2513 OODD Design Doc Flowchart.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_OODD_Design_Doc_Flowchart.png&amp;diff=163636"/>
		<updated>2025-04-08T01:52:51Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162796</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162796"/>
		<updated>2025-03-25T03:58:00Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Routing Tests====&lt;br /&gt;
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
  it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
    expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
    expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
    expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
    expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
    expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests confirm that:&lt;br /&gt;
*All standard RESTful routes are properly configured&lt;br /&gt;
*The routes map to the correct controller actions&lt;br /&gt;
*The routes include the proper namespacing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ProjectTopic Model Tests====&lt;br /&gt;
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup Process&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
  context 'when slots are available' do&lt;br /&gt;
    it 'adds team as confirmed' do&lt;br /&gt;
      expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
      expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it 'removes team from waitlist' do&lt;br /&gt;
      other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
      other_topic.signup_team(team)&lt;br /&gt;
      project_topic.signup_team(team)&lt;br /&gt;
      expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*Teams are properly assigned to available slots&lt;br /&gt;
*When a team signs up for a new topic, it's automatically removed from waitlists of other topics&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Waitlist Management&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when slots are full' do&lt;br /&gt;
  before do&lt;br /&gt;
    2.times do |n|&lt;br /&gt;
      t = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(t)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it 'adds team to waitlist' do&lt;br /&gt;
    new_team = Team.create!(assignment: assignment)&lt;br /&gt;
    expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
    expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a topic reaches maximum capacity, new teams are added to the waitlist&lt;br /&gt;
*The signup process still returns true even when a team is waitlisted&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Drop and Waitlist Promotion&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#drop_team' do&lt;br /&gt;
  before do&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    project_topic.signup_team(Team.create!(assignment: assignment))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context 'when dropping confirmed team' do&lt;br /&gt;
    it 'promotes waitlisted team' do&lt;br /&gt;
      waitlisted_team = Team.create!(assignment: assignment)&lt;br /&gt;
      waitlisted_team2 = Team.create!(assignment: assignment)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team)&lt;br /&gt;
      project_topic.signup_team(waitlisted_team2)&lt;br /&gt;
      &lt;br /&gt;
      expect {&lt;br /&gt;
        project_topic.drop_team(team)&lt;br /&gt;
      }.to change { project_topic.confirmed_teams.count }.by(0)&lt;br /&gt;
      &lt;br /&gt;
      expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false&lt;br /&gt;
      expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*When a confirmed team drops a topic, the first waitlisted team is automatically promoted&lt;br /&gt;
*The promotion follows a FIFO (First-In-First-Out) order&lt;br /&gt;
*The total number of confirmed teams remains constant after the promotion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Slot Availability Calculations&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#available_slots' do&lt;br /&gt;
  it 'returns # of available slots correctly' do&lt;br /&gt;
    expect(project_topic.available_slots).to eq(2)&lt;br /&gt;
    project_topic.signup_team(team)&lt;br /&gt;
    expect(project_topic.available_slots).to eq(1)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe '#slot_available?' do&lt;br /&gt;
  it 'returns true when slots available' do&lt;br /&gt;
    expect(project_topic.slot_available?).to be true&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns false when slots full' do&lt;br /&gt;
    2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) }&lt;br /&gt;
    expect(project_topic.slot_available?).to be false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This test verifies that:&lt;br /&gt;
*The system correctly calculates available slots&lt;br /&gt;
*The slot_available? method accurately reflects whether slots are available&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====SignedUpTeam Model Tests====&lt;br /&gt;
The signed_up_team_spec.rb file tests the join model that connects teams and topics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Validation Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
  it 'requires a project topic' do&lt;br /&gt;
    sut = SignedUpTeam.new(team: team)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'requires a team' do&lt;br /&gt;
    sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
    expect(sut).not_to be_valid&lt;br /&gt;
    expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'enforces unique team per project topic' do&lt;br /&gt;
    SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
    duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
    expect(duplicate).not_to be_valid&lt;br /&gt;
    expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*SignedUpTeam records require both a project_topic and a team&lt;br /&gt;
*A team cannot be signed up for the same topic multiple times&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Scope Tests&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'scopes' do&lt;br /&gt;
  let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) }&lt;br /&gt;
  let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) }&lt;br /&gt;
  &lt;br /&gt;
  it 'returns confirmed signups' do&lt;br /&gt;
    expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  it 'returns waitlisted signups' do&lt;br /&gt;
    expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The confirmed scope returns only non-waitlisted signups&lt;br /&gt;
*The waitlisted scope returns only waitlisted signups&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Team Signup and Removal&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
  it 'delegates to project topic signup' do&lt;br /&gt;
    allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
    result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
    expect(result).to be true&lt;br /&gt;
    expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
describe 'remove_team_signups' do&lt;br /&gt;
  let!(:topic1) { ProjectTopic.create!(topic_name: &amp;quot;Topic 1&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:topic2) { ProjectTopic.create!(topic_name: &amp;quot;Topic 2&amp;quot;, assignment: assignment) }&lt;br /&gt;
  let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) }&lt;br /&gt;
  let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) }&lt;br /&gt;
  &lt;br /&gt;
  it 'removes all team signups across topics' do&lt;br /&gt;
    expect {&lt;br /&gt;
      SignedUpTeam.remove_team_signups(team)&lt;br /&gt;
    }.to change(SignedUpTeam, :count).by(-2)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These tests verify that:&lt;br /&gt;
*The signup_for_topic method correctly delegates to the project_topic's signup_team method&lt;br /&gt;
*The remove_team_signups method removes all signups for a team across all topics&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162758</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162758"/>
		<updated>2025-03-25T03:23:59Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic_routing&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require &amp;quot;rails_helper&amp;quot;&lt;br /&gt;
&lt;br /&gt;
RSpec.describe Api::V1::ProjectTopicsController, type: :routing do&lt;br /&gt;
  describe &amp;quot;routing&amp;quot; do&lt;br /&gt;
    it &amp;quot;routes to #index&amp;quot; do&lt;br /&gt;
      expect(get: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#index&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;routes to #show&amp;quot; do&lt;br /&gt;
      expect(get: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#show&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;routes to #create&amp;quot; do&lt;br /&gt;
      expect(post: &amp;quot;/api/v1/project_topics&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#create&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;routes to #update via PUT&amp;quot; do&lt;br /&gt;
      expect(put: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;routes to #update via PATCH&amp;quot; do&lt;br /&gt;
      expect(patch: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#update&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;routes to #destroy&amp;quot; do&lt;br /&gt;
      expect(delete: &amp;quot;/api/v1/project_topics/1&amp;quot;).to route_to(&amp;quot;api/v1/project_topics#destroy&amp;quot;, id: &amp;quot;1&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#signup_team' do&lt;br /&gt;
    context 'when slots are available' do&lt;br /&gt;
      it 'adds team as confirmed' do&lt;br /&gt;
        expect(project_topic.signup_team(team)).to be true&lt;br /&gt;
        expect(project_topic.confirmed_teams).to include(team)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      it 'removes team from waitlist' do&lt;br /&gt;
        other_topic = ProjectTopic.create!(topic_name: &amp;quot;Other Topic&amp;quot;, assignment: assignment, max_choosers: 1)&lt;br /&gt;
        other_topic.signup_team(team)&lt;br /&gt;
        project_topic.signup_team(team)&lt;br /&gt;
        expect(other_topic.reload.waitlisted_teams).not_to include(team)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when slots are full' do&lt;br /&gt;
      before do&lt;br /&gt;
        2.times do |n|&lt;br /&gt;
          t = Team.create!(assignment: assignment)&lt;br /&gt;
          project_topic.signup_team(t)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      it 'adds team to waitlist' do&lt;br /&gt;
        new_team = Team.create!(assignment: assignment)&lt;br /&gt;
        expect(project_topic.signup_team(new_team)).to be true&lt;br /&gt;
        expect(project_topic.waitlisted_teams).to include(new_team)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when team already signed up' do&lt;br /&gt;
      before { project_topic.signup_team(team) }&lt;br /&gt;
      it 'returns false' do&lt;br /&gt;
        expect(project_topic.signup_team(team)).to be false&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for signed_up_team&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'validations' do&lt;br /&gt;
    it 'requires a project topic' do&lt;br /&gt;
      sut = SignedUpTeam.new(team: team)&lt;br /&gt;
      expect(sut).not_to be_valid&lt;br /&gt;
      expect(sut.errors[:project_topic]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it 'requires a team' do&lt;br /&gt;
      sut = SignedUpTeam.new(project_topic: project_topic)&lt;br /&gt;
      expect(sut).not_to be_valid&lt;br /&gt;
      expect(sut.errors[:team]).to include(&amp;quot;must exist&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it 'enforces unique team per project topic' do&lt;br /&gt;
      SignedUpTeam.create!(project_topic: project_topic, team: team)&lt;br /&gt;
      duplicate = SignedUpTeam.new(project_topic: project_topic, team: team)&lt;br /&gt;
      expect(duplicate).not_to be_valid&lt;br /&gt;
      expect(duplicate.errors[:team]).to include(&amp;quot;has already been taken&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
describe 'signup_for_topic' do&lt;br /&gt;
    it 'delegates to project topic signup' do&lt;br /&gt;
      allow(project_topic).to receive(:signup_team).with(team).and_return(true)&lt;br /&gt;
      result = SignedUpTeam.signup_for_topic(team, project_topic)&lt;br /&gt;
      expect(result).to be true&lt;br /&gt;
      expect(project_topic).to have_received(:signup_team).with(team)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162724</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162724"/>
		<updated>2025-03-25T02:57:12Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic_routing&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for signed_up_team&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162723</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162723"/>
		<updated>2025-03-25T02:56:37Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic_routing&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image1.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for project_topic&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image2.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Tests for signed_up_team&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:E2513_Image3.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/97&lt;br /&gt;
&lt;br /&gt;
Demonstration : https://go.ncsu.edu/testing_video&lt;br /&gt;
&lt;br /&gt;
==Team==&lt;br /&gt;
=====Mentor===== &lt;br /&gt;
*Dinesh Pasupuleti (dpasupu@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
=====Members===== &lt;br /&gt;
*Adithya Srinivasan (asrini27@ncsu.edu)&lt;br /&gt;
*Smiti Kothari (skothar3@ncsu.edu)&lt;br /&gt;
*Dev Patel (dmpatel3@ncsu.edu)&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image3.png&amp;diff=162679</id>
		<title>File:E2513 Image3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image3.png&amp;diff=162679"/>
		<updated>2025-03-25T02:28:02Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image2.png&amp;diff=162676</id>
		<title>File:E2513 Image2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image2.png&amp;diff=162676"/>
		<updated>2025-03-25T02:27:43Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image1.png&amp;diff=162672</id>
		<title>File:E2513 Image1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2513_Image1.png&amp;diff=162672"/>
		<updated>2025-03-25T02:27:17Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162644</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162644"/>
		<updated>2025-03-25T01:57:36Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
   next_team = waitlisted_teams.first&lt;br /&gt;
   return unless next_team&lt;br /&gt;
   signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
   remove_from_waitlist(next_team)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Team Signup/Drop Workflows:&amp;lt;/b&amp;gt; We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:&lt;br /&gt;
**Teams are properly assigned to available slots&lt;br /&gt;
**Waitlisted teams are automatically promoted when a slot open up&lt;br /&gt;
**Duplicate signups are prevented&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Slot Availability Calculations:&amp;lt;/b&amp;gt;Tests confirm the system correctly calculates and updates available slots when:&lt;br /&gt;
**Teams join or leave a topic&lt;br /&gt;
**Topics reach maximum capacity&lt;br /&gt;
**Waitlisted teams are promoted&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Waitlist Ordering:&amp;lt;/b&amp;gt;We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:&lt;br /&gt;
**Tracking creation timestamps&lt;br /&gt;
**Verifying promotion order matches signup sequence&lt;br /&gt;
**Ensuring fairness in team assignments&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;ProjectTopic ↔ Team Relationships:&amp;lt;/b&amp;gt;We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:&lt;br /&gt;
**Proper creation and destruction of join records&lt;br /&gt;
**Cascading deletions when topics or teams are removed&lt;br /&gt;
**Maintenance of referential integrity&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Join Record Validations:&amp;lt;/b&amp;gt;Tests confirm the SignedUpTeam model:&lt;br /&gt;
**Enforces uniqueness constraints (preventing duplicate signups)&lt;br /&gt;
**Validates presence of required associations&lt;br /&gt;
**Maintains proper waitlist status flags&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;CRUD Operation Mapping:&amp;lt;/b&amp;gt;We verify all standard endpoints are properly routed:&lt;br /&gt;
**GET /api/v1/project_topics → index action&lt;br /&gt;
**POST /api/v1/project_topics → create action&lt;br /&gt;
**GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162626</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162626"/>
		<updated>2025-03-25T01:40:34Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
#The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.&lt;br /&gt;
&amp;lt;code&amp;gt;&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&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
  scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
def available_slots&lt;br /&gt;
    max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
  def slot_available?&lt;br /&gt;
    available_slots.positive?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
 def promote_waitlisted_team&lt;br /&gt;
    next_team = waitlisted_teams.first&lt;br /&gt;
    return unless next_team&lt;br /&gt;
    signed_up_teams.find_by(team: next_team)&amp;amp;.update!(is_waitlisted: false)&lt;br /&gt;
    remove_from_waitlist(next_team)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RSpec Testing==&lt;br /&gt;
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 35 scenarios.&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162611</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162611"/>
		<updated>2025-03-25T01:34:02Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#This class should include a method to sign a team up for a topic.&lt;br /&gt;
#It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
====Models====&lt;br /&gt;
&lt;br /&gt;
#SignUpTopic Model&lt;br /&gt;
The current implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.&lt;br /&gt;
&lt;br /&gt;
#SignUpTeam Model&lt;br /&gt;
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.&lt;br /&gt;
&lt;br /&gt;
====Controller====&lt;br /&gt;
&lt;br /&gt;
#ProjectTopicsController&lt;br /&gt;
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics.&lt;br /&gt;
The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.&lt;br /&gt;
&lt;br /&gt;
#SignedUpTeamsController&lt;br /&gt;
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics.&lt;br /&gt;
The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Drawbacks in Current Implementation==&lt;br /&gt;
The current implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.&lt;br /&gt;
The existing ProjectTopic model is extremely basic, containing only association definitions without any of the required functionality for managing topic signups and waitlists. The model lacks methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics to waitlisted teams. This incomplete implementation makes it impossible for the system to properly manage topic signups, which is a critical feature of the Expertiza platform.&lt;br /&gt;
Similarly, the SignedUpTeam model includes basic scopes and validation but lacks the comprehensive waitlist management and topic reassignment functionality needed for a robust implementation. While it includes methods for signing up teams and removing team signups, these methods are not fully implemented and do not handle the complex logic required for waitlist management.&lt;br /&gt;
The controllers are also incomplete, with many methods relying on model functionality that doesn't exist yet. This disconnect between the controller expectations and the model capabilities creates a fragmented system that cannot properly handle the topic signup workflow.&lt;br /&gt;
&lt;br /&gt;
==Solution==&lt;br /&gt;
To address these issues, our reimplementation focuses on:&lt;br /&gt;
#We're implementing a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.&lt;br /&gt;
#Our implementation includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.&lt;br /&gt;
#We're implementing proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.&lt;br /&gt;
#We're implementing RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.&lt;br /&gt;
&lt;br /&gt;
==Code Improvements==&lt;br /&gt;
#The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
def signup_team(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_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;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162574</id>
		<title>CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025_-_E2513._Reimplement_sign_up_topic.rb_as_project_topic.rb&amp;diff=162574"/>
		<updated>2025-03-25T01:03:48Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: Created page with &amp;quot; __TOC__  ==About Expertiza== [http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The reimplementation project consists of:&lt;br /&gt;
#&amp;lt;b&amp;gt;The SignUpTopic class should be reimplemented as ProjectTopic.&lt;br /&gt;
#&amp;lt;b&amp;gt;Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.&lt;br /&gt;
#&amp;lt;b&amp;gt;This class should include a method to sign a team up for a topic.&lt;br /&gt;
#&amp;lt;b&amp;gt;It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.&lt;br /&gt;
#&amp;lt;b&amp;gt;It should include a method that returns the AssignmentTeams signed up for a topic.&lt;br /&gt;
#&amp;lt;b&amp;gt;It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025&amp;diff=162541</id>
		<title>CSC/ECE 517 Spring 2025</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2025&amp;diff=162541"/>
		<updated>2025-03-25T00:50:29Z</updated>

		<summary type="html">&lt;p&gt;Asrini27: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[CSC/ECE 517 Spring 2025 - E2504. Mentor-meeting management]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2505. Testing Answer Tagging]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2508. Reimplement bidding-algorithm web service]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2509. Reimplement feedback_response_map.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2024 - E2519. Implement view for results of bidding]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2522. Enhancing UI Consistency in Expertiza 1]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2520. Reimplement heatgrid UI for reviews]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2517. Reimplement internationalization (frontend + backend)]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2523: Enhancing UI Consistency in Expertiza 2]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2515:  Reimplement student_teams_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2501:  Refactor review_mapping_helper.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2502:  Refactor review_mapping_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2512. Reimplement responses controller]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2510. Reimplement grades_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2507. Reimplement back end for submission records]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2514. Reimplement student_quizzes_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2518. Reimplement password resets (frontend + backend)]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2516. Reimplement teams_users_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2511. Reimplement participants_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2521. UI for View submissions/assign grades (except heatgrid)]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2025 - E2513. Reimplement sign_up_topic.rb as project_topic.rb]]&lt;/div&gt;</summary>
		<author><name>Asrini27</name></author>
	</entry>
</feed>