
This project, QuickHire, is built upon the Address Book Level 3 (AB3) project originally developed by the SE-EDU initiative. We extend our heartfelt thanks to the AB3 developers for laying the foundation that shaped our project’s structure and functionality.
We also gratefully acknowledge the creators of the following resources, libraries, and tools that were instrumental in bringing QuickHire to life:
Their contributions and expertise made our work possible, and we deeply appreciate their support.
Additionally, we would like to thank StackOverflow. We had some inspiration for some of our features from the valuable answers provided by experienced coders in the platform.
Refer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main (consisting of classes Main and MainApp) is in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI: The UI of the App.Logic: The command executor.Model: Holds the data of the App in memory.Storage: Reads data from, and writes data to, the hard disk.Commons represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.
Each of the four main components (also shown in the diagram above),
interface with the same name as the Component.{Component Name}Manager class (which follows the corresponding API interface mentioned in the previous point.For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter etc. All these, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
The UI component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
The UI component,
Logic component.Model data so that the UI can be updated with the modified data.Logic component, because the UI relies on the Logic to execute commands.Model component, as it displays Person object residing in the Model.API : Logic.java
Here's a (partial) class diagram of the Logic component:
The sequence diagram below illustrates the interactions within the Logic component, taking execute("delete 1") API call as an example.
Note: The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the Logic component works:
Logic is called upon to execute a command, it is passed to an AddressBookParser object which in turn creates a parser that matches the command (e.g., DeleteCommandParser) and uses it to parse the command.Command object (more precisely, an object of one of its subclasses e.g., DeleteCommand) which is executed by the LogicManager.Model when it is executed (e.g. to delete a person).Model) to achieve.CommandResult object which is returned back from Logic.Here are the other classes in Logic (omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AddressBookParser class creates an XYZCommandParser (XYZ is a placeholder for the specific command name e.g., AddCommandParser) which uses the other classes shown above to parse the user command and create a XYZCommand object (e.g., AddCommand) which the AddressBookParser returns back as a Command object.XYZCommandParser classes (e.g., AddCommandParser, DeleteCommandParser, ...) inherit from the Parser interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model component,
Person objects (which are contained in a UniquePersonList object).Person objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Person> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.UserPref object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref objects.Schedule objects as a separate list which is exposed to outsiders as an unmodifiable ObservableList<Schedule> that can be observed.Model represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a JobRole list in the AddressBook, which Person references.
API : Storage.java
The Storage component,
AddressBookStorage, UserPrefStorage, and ScheduleBoardStorage which means it can be treated as either of the three (if only the functionality of only one is needed).Model component (because the Storage component's job is to save/retrieve objects that belong to the Model)Classes used by multiple components are in the seedu.address.commons package.
This section describes some noteworthy details on how certain features are implemented.
Note
Candidate are referred to as Person throughout the codebase due to legacy design choices.
The Add Candidate and Add Schedule features both adhere to the Logic Component format described above and share a similar implementation structure.
As an example, below is the sequence diagram for the Add Candidate command when the user inputs:
add n/Vish p/1293123 e/sample@domain.com a/213123 street j/ProData guy l/Rejected
Note
The implementation of the Add Schedule feature is similar to that of the example given above. However, instead of calling hasPerson(...), hasJobRoles(...), and addPerson(...) methods,
the methods hasSameDateTime(...) and addSchedule(...) in Model component will be called for adding a schedule.
The Edit Candidate and Edit Interview Schedule features both adhere to the Logic Component format described above and share a similar implementation structure.
As an example, below is the sequence diagram for the Edit Candidate command when the user inputs:
edit 1 p/91234567 e/johndoe@example.com
Note
The implementation of the Edit Schedule feature is similar to that of the example given above. However,
the methods createEditedSchedule(...), hasSameDateTimeEdit(...), setSchedule(...), and updateFilteredScheduleList(...) in Model component will be called for adding a schedule.
The Delete Candidate and Delete Schedule features both adhere to the Logic Component format described above and share a similar implementation structure.
As an example, below is the sequence diagram for the Delete Candidate command when the user inputs:
delete 1
Note
The implementation of the Delete Schedule feature is similar to that of the example given above. However, instead of calling getFilteredPersonList() and deletePerson(...) methods,
the methods getFilteredScheduleList() and deleteSchedule(...) in Model component will be called for deleting a schedule.
The List and Clear Candidate/Interview Schedules commands deviate slightly from the Logic Component format above because they require no arguments and thus bypass the Parser. Since both commands follow the same flow, we’ll illustrate only the sequence diagram for the Clear Candidates command when the user enters:
clear
Main execution steps:
User Input: The user enters clear to clear all candidates.
Parsing: LogicManager calls parseCommand("clear") on AddressBookParser.
Command Creation: AddressBookParser recognizes the clear command and directly instantiates ClearCommand (no arguments to parse).
Execution: LogicManager invokes execute(model) on the ClearCommand.
Listing: ClearCommand clear the current candidate list and updates the model.
Result: ClearCommand returns a CommandResult indicating success, which LogicManager then propagates back to the UI.
Note
The implementation of the List Candidates feature is similar to that of the example given above. However, instead of setAddressBook(...) method of the Model Component being called, updateFilteredPersonList(...) is called.
For Listing and Clearing schedules, the methods updateFilteredScheduleList(...) and setScheduleBoard(...) in Model component will be called respectively.
The Storage component is used to save data automatically whenever a change to the data occurs. While the same
component can be used to store data manually, there are some limitations:
Storage inherits from AddressBookStorage, ScheduleBoardStorage and UserPrefsStorage, any class implementing Storage will have to
adhere to the contracts of all three interfaces. While it makes sense for the general scope of the application, it doesn't make sense
when the user only wishes to save data to a particular location at a particular point in time (and they do not necessarily wish to permanently save
the data to this chosen location).UserPrefsStorage, and return dummy values like Optional#empty() for readUserPrefs() or an empty String for getUserPrefsFilePath()UserPrefsStorage.ManualStorage AddressBookStorage and ScheduleBoardStorage.ManualStorageManager, will implement ManualStorage and implement methods for reading and writing data pertaining to candidates and interview schedules.Storage and StorageManager, the benefit is that, to store data manually, classes and objects no longer have to worry about dealing with user preferences.
The theme command is used to change the theme of the GUI to either light or dark theme.
The theme command was implemented after the theme button.
themeCommand and Theme classes and it is similar to the handling of the other commands to some extent.themeCommandParser class and the
themeCommandclass's exectue method returns a commandResult.GUISettings are saved through the UserPrefs class along with relevant methods to execute the same.viewstats commandThe viewstats command is used to display job applicant statistics grouped by job roles in a dedicated statistics window. The viewstats command was implemented after the initial set of core commands (like help and list).
ViewStatsCommand class and it is similar to the handling of other commands to some extent.ViewStatsCommandParser class is used to parse the command input ("viewstats").ViewStatsCommand class's execute(...) method returns a CommandResult.execute(...) is called, the ViewStatsCommand aggregates job application statistics by calling getJobApplicantStatistics() on the Model.CommandResult holds a mapping of job roles to applicant counts.MainWindow detects that the command result contains statistics and opens (or focuses) a StatisticsWindow.StatisticsWindow is set to be:
ModelManager#getFilteredJobRolesList(), which is used to render the chart.Below is the sequence diagram showing how viewstats is parsed, executed, and displayed:
Note
The
StatisticsWindowdesign uses similar principles to theHelpWindow. The main difference is thatStatisticsWindowdisplays a bar chart (inStatisticsPanel.fxml) rather than static text. Additionally, the window is strictly non-resizable and will not allow multiple instances to appear simultaneously.
{Explain here how the data archiving feature will be implemented}
Target user profile:
Value proposition: to be able to manage candidates' details and provide a more efficient way to organize potential candidates to their company compared to traditional methods. It is optimized for hiring recruiters who prefer a CLI.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * | user | add a new applicant's contact details | start adding new applicant's details into the application quickly |
* * * | user | list all applicants' contact | verify the stored data |
* * * | user | delete applicant's contact | remove applicants that are no longer applying for a job |
* * * | user | exit the application | |
* * | user | label a candidates application status | keep track of applicants status and prioritise those who are yet unreviewed |
* * | user | have all my applicant's contact saved automatically | use the application without losing any changes made |
* * | user | find an applicant's contact | locate details of persons without having to go through the entire list |
* * | new user | view usage instructions | refer to instructions when I forget how to use the application |
* * | user | edit an applicant's contact | rectify any discrepancies in the applicant's contact details |
* * | new user | import my list of applicant's contact | seamlessly migrate data from using one device to this another |
* * | user | add remarks to an applicant's contact details | note down interesting details about a candidate |
* * | user | backup the data of past applicants | recover the data in case of any issues |
* * | user | view statistics of applications to a specific role | make informed decisions on recruiting priorities |
* * | user | add an interview schedule for a candidate | keep track of upcoming interviews and stay organized |
* * | user | delete an interview schedule for a candidate | remove outdated or cancelled interviews |
* * | user | edit an interview schedule for a candidate | update interview details when changes occur |
* * | user | clear all interview schedules | reset the schedule for re-planning or when starting a new recruitment cycle |
* * | user | manually save data pertaining to applicants and their interview schedules | backup the data for archival and recovery purposes |
* * | user | filter through job titles easily | shortlist candidates to fill the vacant job position |
* | new user | play around with sample data | gain more familiarity with using the application |
* | user | change the theme of the UI | use whichever I prefer based on my vison and environment |
Use case: UC01 - Listing candidates
MSS
User requests the list of candidate
QuickHire shows the list of candidate
Use case ends.
Extensions
2a. The list is empty.
Use case ends.
Use case: UC02 - Add a candidate
MSS
User requests to add a candidate
QuickHire adds a new candidate
Use case ends.
Extensions
2a. Duplicate candidate.
Use case ends.
2b. The given parameters are invalid
2b1. QuickHire shows an invalid parameter error message.
Use case ends.
Use case: UC03 - Delete a candidate
MSS
Use case ends.
Extensions
2a. The given index is out of range.
2a1. QuickHire shows and OutOfRange error.
Use case resumes at step 2.
2b. The given parameters are invalid.
2b1. QuickHire shows an error message.
Use case ends.
Use Case: UC04 - Exiting the Application
MSS
User requests to exit the application
QuickHire exits the application
Use case ends.
Use Case: UC05 - Edit a candidate information
MSS
Use case ends.
Extension
2a. The list is empty.
Use case ends.
2b. The given index is invalid.
2b1. QuickHire shows an error message.
Use case resumes at step 2.
2c. The given parameters are invalid.
2c1. QuickHire shows an error message.
Use case ends.
Use Case: UC06 - Adding remarks to a candidate
MSS
User requests to add remarks to a candidate
QuickHire adds the given remark to the candidate's details
Use case ends.
Use Case: UC07 - Finding candidate(s)
MSS
User request to find candidate using some keywords
QuickHire shows the list of candidate matching the provided keywords
Use case ends.
Extensions
2a. The list is empty (i.e., keywords did not match any applicants).
2a1. Notify user about the empty list.
Use case ends.
Use Case: UC08 - Viewing statistics of applications to a specific job
MSS
Extensions
2a. The stats list is empty (i.e., no one applied for a job)
2a1. Notify user about empty list
Use case ends.
Use Case: UC09 - Saving details of candidate into a file
MSS
User requests to save data of candidate and interview schedules into two separate files
QuickHire saves the displayed list of candidate and interview schedules into the specified files
Use case ends.
Extensions
2a. User requests to save all applicants into the file
2a1. QuickHire saves all applicants into the file
Use case ends.
2b. File(s) specified by user already exists in the system
2b1. QuickHire displays error message saying that the file(s) already exists
Use case ends.
2c. File(s) specified by user already exists in the system, and user requests to overwrite any existing file
2c1. QuickHire saves details of applicants to the file(s) (without any errors)
Use case ends.
2d. User does not provide either file
2d1. QuickHire display error message indicating the command format
Use case ends.
Use Case: UC10 - Saving details of filtered data (of candidate)
MSS
User finds candidates (UC07)
User requests to save candidates into a file
QuickHire saves the displayed list of candidates into a file
Use case ends.
Extensions
2a. File exists and user did not request to overwrite file
2a1. Notify user that file already exists
Use case ends.
2b. User requests to save all data
2b1. Save all data (instead of just filtered ones) into file
Use case ends.
Use case: UC11 - Listing interview schedules
Similar to use case 01 except for using to list schedules
Use case: UC12 - Adding an interview schedule
MSS
User requests to add an interview schedule
QuickHire adds a new schedule
Use case ends.
Extensions
2a. Timing clashed with existing interview schedules.
2a1. QuickHire shows an error message.
Use case ends.
2b. The given parameters are invalid.
2b1. QuickHire shows an error message.
Use case ends.
Use case: UC13 - Delete an interview schedule
Similar to use case 03 except for using to delete an interview schedule.
Use Case: UC14 - Edit an interview schedule
MSS
Use case ends.
Extension
2a. The list is empty.
Use case ends.
2b. The given index is invalid.
2b1. QuickHire shows an error message.
Use case resumes at step 2.
2c. The given parameters are invalid.
2c1. QuickHire shows an error message.
Use case ends
Use case: UC15 - Clear all interview schedules
MSS
User requests to clear the list of interview schedules
QuickHire shows the empty list of interview schedules
Use case ends.
Use Case: UC16 - Changing theme of the UI
MSS
User requests to change theme to a specific theme
QuickHire changed to requested theme
Use case ends.
Extensions
1a. User specified incorrect theme
1b1. Notify user of incorrect value
Use case ends.
Use case: UC17 - Listing job roles
Similar to UC01 - Listing candidates except it is for job role instead of candidates
Use case: UC18 - Add a job role
Similar to UC02 - Add a candidate except it is for job role instead of candidates
Use case: UC19 - Delete a job role
Similar to UC03 - Delete a candidate except it is for job role instead of candidates
17 or above installed.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the jar file and copy into an empty folder
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
Saving window preferences
Resize the window to an optimum size. Move the window to a different location. Close the window.
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
{ more test cases … }
Adding a person while all candidates are being shown (valid and invalid)
Prerequisites: No entry below is already in the candidate list.
Test case: add n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 j/Data Scientist l/Unreviewed r/Likes to code t/friends t/owesMoney
Expected: Candidate is added to list. Details of the added contact shown in the result box.
Test case: add
Expected: No candidate is added. General error details shown in the result box.
Test case: add n/Vish p/1293123 e/sample@domain.com a/213123 street l/Rejected
Expected: No candidate is added. Specific error message detailing missing fields shown. (Job Role missing)
Adding a person : Testing duplicate entries
Prerequisites: The same person is already in the candidate list.
Test case: add n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 j/Data Scientist l/Unreviewed r/Likes to code t/friends t/owesMoney
Expected: Candidate is already in list. Duplicate error message shown.
Adding a person : Testing individual parameters
Prerequisites: The same person is already in the candidate list.
Test case: add n/John Who p/98765431 e/johnw@example.com a/311, Clementi Ave 2, #02-25 j/Data Scientist l/funny r/Likes to code t/friends t/owesMoney
Expected: No candidate is added. Label is not in valid format error message shown.
Test case: add n/John Who p/98765431 e/yeetus.example.com a/311, Clementi Ave 2, #02-25 j/Data Scientist l/funny r/Likes to code t/friends t/owesMoney
Expected: No candidate is added. Email is not in valid format error message shown.
The test cases may be repeated for all parameters in a similar fashion.
{ more test cases … }
Deleting a person while all persons are being shown
Prerequisites: List all persons using the list command. Multiple persons in the list.
Test case: delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
Test case: delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
Other incorrect delete commands to try: delete, delete x, ... (where x is larger than the list size)
Expected: Similar to previous.
Adding a schedule that does not overlap with existing schedule
2025-05-03 09:00 10:00 exists and there is at least 1 candidate in the candidate list.sadd c/1 s/2025-05-03 15:00 17:00 m/online 2025-05-03 15:00 17:00, mode online along with the name and email of first candidate is created. Details of the schedule created is shown in the message box. Schedule board shows newly created schedule.Adding a schedule that overlap with existing schedule
2025-05-16 14:00 16:00 exist and there are at least 1 candidate in the candidate list.sadd c/1 s/2025-05-16 14:00 15:00 m/online Editing one or more details of a schedule
Prerequisites: Interview schedule with date and duration 2025-05-03 15:00 17:00 does not exist and the mode of first interview schedule in the list is online.
Test case: sedit 1 s/2025-05-03 15:00 17:00
Expected: Date and duration of the first schedule is changed to 2025-05-03 15:00 17:00. Details of the edited schedule is shown in the message box. Schedule board shows newly edited schedule.
Test case: sedit 1 m/offline
Expected: Mode of the first schedule is changed to offline. Details of the edited schedule is shown in the message box. Schedule board shows newly edited schedule.
Editing date and duration of a schedule to clash with another schedule in the schedule board
Prerequisites: Schedule with date and duration 2025-05-04 14:00 15:00 exists
Test case: sedit 1 s/2025-05-04 14:00 14:30
Expected: Date and duration of first schedule is not updated. Error message is shown in the message box.
Deleting a schedule while all schedules are being shown
Prerequisites: List all schedule using the slist command. Multiple schedules in the list.
Test case: sdelete 1
Expected: First schedule is deleted from the list. Details of the deleted schedule shown in the status message.
Test case: sdelete 0
Expected: No schedule is deleted. Error details shown in the status message.
Other incorrect delete commands to try: sdelete, sdelete x, ... (where x is larger than the list size)
Expected: Similar to previous.
Manually saving the data of the program
Prerequisites: You should have sufficient write permissions to the file path you are saving the data to.
Test case: save c/candidates.json s/schedules.json
[JAR file location]/candidates.json and [JAR file location]/schedules.json, should be created with the corresponding filtered candidates and schedules data respectively.[JAR file location]/candidates.json exists): An error message specifying that [JAR file location]/candidates.json exists.[JAR file location]/schedules.json): An error message specifying that [JAR file location]/schedules.json exists.[JAR file location]/candidates.json exists.
Test case: save c/candidates.json
[JAR file location]/candidates.json should be created with the corresponding filtered candidates data.[JAR file location]/candidates.json exists.Test case: save s/schedules.json
[JAR file location]/schedules.json, should be created with the corresponding schedules data.[JAR file location]/schedules.json exists.Test case: save c/candidates.json s/schedules.json /f
[JAR file location]/candidates.json and [JAR file location]/schedules.json, should be created with the corresponding filtered candidates and schedules data respectively.Test case: save c/candidates.json /f
[JAR file location]/candidates.json should be created with the corresponding filtered candidates data.Test case: save s/schedules.json /f
[JAR file location]/schedules.json, should be created with the corresponding schedules data.Test case: save c/candidates.json /f with and without /a flag
find command[JAR file location]/candidates.json, should be created with the corresponding filtered candidates data./a flag without running list: save c/candidate.json /f /a[JAR file location]/candidates.json, should be created with all corresponding candidates data.Test case: save
Changing the theme of the program.
Prerequisites: none
Test case: theme light
Expected: UI switches to light theme. Help window switches to light theme. Viewstats command switches theme to light theme. Theme Changed message displayed.
Note: The same may be repeated for theme dark.
Test case: theme blue
Expected: Error message displayed, theme does not change.
Change theme is saved.
theme light followed by exit . Reopen the jar file. { more test cases … }
Difficulty level: QuickHire is considerably challenging because of the integration of additional entities and the complexity of managing the relationships between them.
Challenges faced:
Schedule and connects it with Person through Name and Email.Effort required:
Achievements:
Team size: 5
UNRECOGNISED the next time the application is loaded. We plan to notify users which candidates have such job role and provide users with an easier way of updating them.