Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Appendix: Planned Enhancements
Acknowledgements
- The CS2103T teaching team for providing us with the base project that Teachstack builds upon, as well as for their invaluable guidance throughout this project’s development.
- The idea for clickable email was inspired from a similar feature in project CodeConnect.
- Testing of UI components are done with Mockito.
- Any other libaries or 3rd-party code already used in the base project. (see link for details)
Setting up, getting started
Refer to the guide Setting up and getting started.
Design

.puml
files used to create diagrams in this document docs/diagrams
folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
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.
- At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
- At shut down, it shuts down the other components and invokes cleanup methods where necessary.
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 view A0123456X
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
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.
UI 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,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object residing in theModel
.
Logic component
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 A0123456X")
API call as an example.

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:
- When
Logic
is called upon to execute a command, it is passed to anAddressBookParser
object which in turn creates a parser that matches the command (e.g.,DeleteCommandParser
) and uses it to parse the command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,DeleteCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to delete a person).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and theModel
) to achieve. - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
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:
- When called upon to parse a user command, the
AddressBookParser
class creates anXYZCommandParser
(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 aXYZCommand
object (e.g.,AddCommand
) which theAddressBookParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the address book data i.e., all
Person
objects (which are contained in aUniquePersonList
object). - stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<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. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)

Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.
Storage component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
- inherits from
AddressBookStorage
,ArchivedBookStorage
,UserDataStorage
andUserPrefStorage
, which means it can be treated as any one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Group feature
Implementation
The group feature is a modification of the original “tag” feature, where each Person
can have multiple tags with various sorts of information.
We have adapted the tags for the express purpose of putting students into groups.
The command, like all others, implements execute
. If possible, all students will be put into the specified group.
A valid student needs to have a studentId
which fulfils various criteria as specified in the StudentId
class.
A valid student should also be in the list of current students. If any students are invalid, the whole command fails.
Students who are not in the list of existing students are given in the exception message of GroupCommand
itself.
Internally, the command makes use of the pre-existing EditCommand#execute(StudentId, editPersonDescriptor)
method.
It calls this method for all given students in a loop.
It is also possible to give no argument for groups
.
In which case, the students given will have their groups set to none (i.e., removed).
Given below is an example usage scenario:
Step 1. The user enters command group gp/3 id/A0123456X id/A0000000H
where
id/A0123456X
is in the list of existing students, but id/A0000000H
is not.
In this case, id/A0123456X
is not in the list of existing students, so the whole command fails.
Step 2. The user then enters command group gp/3 id/A0123456X
.
The group
command calls EditCommand#execute(StudentId, editPersonDescriptor)
for id/A0123456X
.
Hence, the student is added to group 3.
Step 3. The user then enters command group gp/7 id/A0123456X id/A1234567H
.
Since both students are in the list, they are both added to group 7.
Note that p0
still retains the original group, group 3.
Design Considerations
Aspect: Whether to allow partial success of command (i.e. successfully add some students even if only some provided IDs are valid)
-
Alternative 1 (current choice): Disallow partial success.
- Pros:
- Leads to less confusion regarding whether students are successfully added to a group or not (either they all are, or they all aren’t.)
- Is the standard expectation of a CLI command.
- Cons: Will have to retype command if it fails.
- Pros:
-
Alternative 2: Allow partial success.
- Pros and cons are the opposite of those of alternative 1.
Add Feature
Implementation
The add feature is similar to the add feature in AB3, which allows users to add students’ details into the list.
However, in our implementation, we decided to extend the add feature to add students’ details such as, name
, student_id
, email
, grade
, group
that is tailored to our target audience.
Given below is an example usage scenario:
Step 1. Assume the user has some existing students in the UniquePersonList
.
Step 2. The user executes add id/A0123456X n/John e/e0123456@u.nus.edu g/A
command to add the student into the list.
- The
add
command invokesLogicManager#execute()
. -
LogicManager#execute()
would first invokeAddressBookParser#parseCommand()
. -
AddressBookParser#parseCommand()
will identify theadd
command and then invokeAddCommandParser#parse()
to parse the arguments accordingly. -
AddCommandParser#parse()
will return aAddCommand
object which takes in aPerson
object. -
LogicManager#execute()
invokesAddCommand#execute()
. Then,model#addPerson
is called to add the person into the list.
Given below is the sequence diagram for add
command:
Design Considerations
Aspect: Whether to restrict to the context of NUS
-
Alternative 1 (current choice): The
student_id
andemail
must be in the format ofA0123456X
ande0123456@u.nus.edu
.- Pros: Aligns with the target users who are CS instructors in NUS.
- Cons: Restrictive to users who are not instructors in NUS.
-
Alternative 2: Allow any other format for
student_id
and valid format foremail
.- Pros: Can accommodate users from other universities, not only NUS.
- Cons: Validation may be more complex as we need to account for a wider range of possible inputs.
Delete feature
Implementation
The delete feature is adapted from the delete feature of AddressBook
. Instead of identifying a student by the index displayed, it uses the StudentId
that is unique to each student. Calling DeleteCommand#execute(model)
will delete any student that is in the UniquePersonList
that is not necessarily in but not in FilteredList
to be deleted.
Given below is an example usage scenario:
Step 1. The user has added some students to UniquePersonList
.
Step 2. The user executes find
command where only student1
and student2
matches the predicate so only student1
and student2
are in the FilteredList
of ModelManager
.
Step 3. The user executes delete A0123456A
command to delete student with student ID A0123456A
. ModelManager#getPerson(StudentId)
returns student3
which the id belongs to. student3
will be removed from UniquePersonList

ModelManager#getPerson(StudentId)
returns 0, then there no Person
having the studentId
. DeleteCommand#execute(model)
will check if this is the case. If so, it will return an error to the user rather
than attempting to perform the deletion.
The following sequence diagram shows how a delete operation goes through the Logic
component:

DeleteCommandParser
and DeleteCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of the diagram.
The following activity diagram summarizes what happens when a user executes a delete command:
Design Considerations
Aspect: Allow deletion of all Person
added or only those displayed
-
Alternative 1 (current choice): Can delete any
Person
in thepersons
list.- Pros: Delete command will execute successfully without having to run additional command to ensure that the
Person
to be deleted is being displayed. - Cons: May result in accidental deletion if wrong student id is given.
- Pros: Delete command will execute successfully without having to run additional command to ensure that the
-
Alternative 2: Only delete
Person
that is displayed.- Pros: Allow user to refer to the displayed data to reduce risk of specifying a wrong id belonging to another
Person
. - Cons: May reduce usability as user may have to enter additional command to ensure the student to be deleted is displayed.
- Pros: Allow user to refer to the displayed data to reduce risk of specifying a wrong id belonging to another
Aspect: Deleted Person
stored or ready for garbage collection
-
Alternative 1 (current choice):
Person
deleted is no longer used and ready for garbage collection.- Pros: Easy to implement.
- Cons: May result in lost of data upon accidental deletion.
-
Alternative 2: Create a list to store all deleted
Person
.- Pros: Easier to implement command to recover a deleted
Person
in the future. - Cons: Stored deleted
Person
may never be used. May have performance issue in terms of memory usage.
- Pros: Easier to implement command to recover a deleted
Find feature
Implementation
Our find feature is a rework of the one found in AB3, which allowed users to find persons with names containing specified keywords. Since we now have a stronger method of identifying students (their unique student IDs), we decided to update the feature to find and list students by their membership in groups instead.
A FindCommand
instance has its own PersonInGroupPredicate
, which contains a Set<Group>
and is used to test if a Person
is in the Group
s in the set. These groups are specified as arguments when entering the find command. It is also important to note that the Person
must be in all the Group
s in the set in order to pass the predicate.
When FindCommand#execute(model)
is called, ModelManager#updateFilteredPersonList(predicate)
is invoked to update the filter of the currently shown FilteredList` to match the predicate.
Given below is an example usage scenario:
Step 1. The user launches the application. The initial list shown is simply the UniquePersonList
.
Step 2. The user executes find gp/Group 1 gp/Group 2
to find all students that are in both Groups 1 and 2. Only student1
is in both groups, so after ModelManager#updateFilteredPersonList(predicate)
is called, only student1
will be in the FilteredList
.
Here is the sequence diagram which shows the overall flow:

FindCommandParser
and FindCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of the diagram.
Design Considerations
Aspect: Which model attribute to use for find
-
Alternative 1 (current choice): Filter by
Group
- Pros:
Group
names are easy to remember, especially since they are assigned by the user. - Cons: Some students may not have a
Group
assigned and can only be found by manually looking through all entries inUniquePersonList
.
- Pros:
-
Alternative 2: Filter by
StudentId
- Pros: Any student can be found as long as their
StudentId
is known. - Cons: It is not practical for users to remember the
StudentId
of each student.
- Pros: Any student can be found as long as their
Random feature
Implementation
The random feature is an extension of the group feature. It creates a GroupCommand
object to form groups, by passing a random set of studentIds
and group
of size 1 to the constructor.
When RandomCommand#execute(model)
is called, it will filter UniquePersonList
in Model
to get a List<Person>
of students where each student matches the predicate person.isWeak()
. The randomness is achieved using Collections#shuffle(List<Person>)
, to randomly reorder the List<Person>
. Note that the result is approximately random where probability of getting each permutation of the list is approximately equal.
Given below is an example usage scenario:
Step 1. The user launches the application for the first time. The Grade#thresholdGrade.value
is set to C+
. There are some students in the UniquePersonList
.
Step 2. The user executes random 2 gp/Random Group
to put all students having Grade#value
below or equals to C+
into 2 groups namely Random Group 1
and Random Group 2
.

ModelManager#getWeak()
returns List<Person>
of size less than or equals to the positive integer given in command, the RandomCommand#execute(model)
will throw a CommandException
.

Group
objects created will always be the same when the same command is given and the UniquePersonList
is the same Step 1. However, the association between Person
and Grade
objects may be different each time due to the randomness.
The following sequence diagram shows how a random command goes through the Logic
component:

RandomCommandParser
and RandomCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The following activity diagram summarizes what happens when a user executes a random command:
Design Considerations
Aspect: Allow forming groups if number of weak students is equals to the group number specified
-
Alternative 1 (current choice): Random command will not form any group.
- Pros: Command will not result in groups containing only one student since it will not actually group any students and is not very helpful.
- Cons: May restrict the use case where user wants to have a focus session with weak students individually.
-
Alternative 2: Random command will form groups.
- Pros: Allow forming of groups with only one student, less likely to trigger an error message.
- Cons: May reduce usability as user may not get an actual group of multiple students as expected.
Aspect: Clear Group
formed using the RandomCommand
when thresholdGrade
is updated and Grade
of the Person
is no longer below or at the threshold
-
Alternative 1 (current choice): Random groups formed will not be affected by any change in threshold.
- Pros: Easy to implement. Random groups formed may still be active and needed for record.
- Cons: User has to rerun the
random
command to form groups for the updated weak students.
-
Alternative 2: Remove
Person
from random groups formed ifGrade
of thePerson
is no longer below or at the threshold.- Pros: User can use the same groupings for weak students who still require more focus on.
- Cons: More complicated to implement and record of previous random groupings a
Person
belongs to will be gone.
Archive feature
Implementation
The archive feature allows the users to keep a record of past students’ details.
Given below is an example usage scenario:
Step 1. Assume the user has some existing students in the UniquePersonList
of persons
list.
Step 2. The user executes archive A0123456X
to archive the student into the archived list.
- The
archive
command invokesLogicManager#execute()
. -
LogicManager#execute
would first invokeAddressBookParser#parseCommand()
. -
AddressBookParser#parseCommand()
will identify thearchive
command and then invokeArchiveCommandParser#parse()
to parse the arguments accordingly. -
ArchiveCommandParser#parse()
will return anArchiveCommand
object which takes in aStudentId
object. -
LogicManager#execute()
invokesArchiveCommand#execute()
. Then,model#archivePerson
is called to archive the student into the archived list. - The archived student will now be added into
UniquePersonList
of the archived list. - The archived student will also be removed from the
UniquePersonList
of thepersons
list.
Given below is the sequence diagram for archive
command:

ArchiveCommandParser
and ArchiveCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Design Considerations
Aspect: Mass archiving
-
Alternative 1 (current choice): Allow archiving only one student at a time.
- Pros: Reduce the complexity of archiving process for the users.
- Cons: May be time-consuming for users who need to archive multiple students.
-
Alternative 2: Allow users to select and archive multiple students at once.
- Pros: Increases efficiency by allowing users to archive multiple students simultaneously.
- Cons: May increase the risk of unintentional archiving.
Unarchived feature
Implementation
The unarchived feature allows the users to unarchive past students’ details.
Given below is an example usage scenario:
Step 1. Assume the user has some existing students in the UniquePersonList
of archived list.
Step 2. The user executes unarchived A0123456X
to unarchive the student into the persons
list.
- The
unarchive
command invokesLogicManager#execute()
. -
LogicManager#execute
would first invokeArchivedBookParser#parseCommand()
. -
ArchivedBookParser#parseCommand()
will identifies theunarchived
command and then invokesUnarchiveCommandParser#parse()
to parse the arguments accordingly. -
UnarchiveCommandParser#parse()
will return aUnarchiveCommand
object which takes in aStudentId
object. -
LogicManager#execute()
invokesUnarchiveCommand#execute()
. Then,model#unarchivePerson
is called to unarchive the archived student into thepersons
list. - The archived student will now be added into
UniquePersonList
of thepersons
list. - The archived student will also be removed from the
UniquePersonList
of the archived list.
Given below is the sequence diagram for unarchived
command:

UnarchivedCommandParser
and UnarchivedCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Design Considerations
Aspect: Mass unarchiving
-
Alternative 1 (current choice): Allow unarchiving only one student at a time.
- Pros: Reduce the complexity of unarchiving process for the users.
- Cons: May be time-consuming for users who need to unarchive multiple students.
-
Alternative 2: Allow users to select and unarchive multiple students at once.
- Pros: Increases efficiency by allowing users to unarchive multiple students simultaneously.
- Cons: May increase the risk of unintentional unarchiving.
Edit_Archived feature
Implementation
The edit_archived feature is similar to the edit feature. However, edit_archived is only applicable to edit students in the archived list.
Given below is an example usage scenario:
Step 1. Assume the user has some existing students in the UniquePersonList
of archived list.
Step 2. The user executes edit_archived A0123456X g/B
to edit the student’s grade to ‘B’ in the archived list.
- The
edit_archived
command invokesLogicManager#execute()
. -
LogicManager#execute
would first invokeArchivedBookParser#parseCommand()
. -
ArchivedBookParser#parseCommand()
will identify theedit_archived
command and then invokeEditArchiveCommandParser#parse()
to parse the arguments accordingly.-
EditArchiveCommandParser#parse()
will return anEditArchiveCommand
object which takes in aStudentId
object andEditPersonDescriptor
object.
-
-
LogicManager#execute()
invokesEditArchiveCommand#execute()
. Then,model#setArchivedPerson
is called to replace thepersonToEdit
with theeditedPerson
. - Lastly, the
model#updateFilteredArchivedList()
is called to update the archived list with the editedPerson.
Given below is the sequence diagram for edit_archived
command:

EditCommandParser
and EditCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Delete_Archived feature
Implementation
The delete_archived feature is similar to the delete feature. However, delete_archived is only applicable to delete students in the archived list.
Given below is an example usage scenario:
Step 1. The user has added some students to UniquePersonList
of the archived list.
Step 2. The user executes find
command where only student1
and student2
matches the predicate so only student1
and student2
are in the FilteredArchivedList
of ModelManager
.
Step 3. The user executes delete_archived A0123456A
command to delete student with student ID A0123456A
. ModelManager#getArchivedPerson(StudentId)
returns student3
which the id belongs to. student3
will be removed from UniquePersonList
of the archived list.
Given below is the sequence diagram for delete_archived
command:

DeleteArchiveCommandParser
and DeleteArchiveCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Set Weakness Threshold Feature
Implementation
This is a new command to designate students as being “weak” or not based on their grades. thresholdGrade
is a value
within Grade
. This does not affect students who have been archived.
By default, we have set C+ as the thresholdGrade
, meaning that a student with grade lower than or equal to C+ is
displayed with a weak marker next to their name (as shown below).
The command set weak g/GRADE
followed by the grade parameter allows the instructor to set a different grade as the
new thresholdGrade
. This command resets students’ weak markers and updates the display immediately.
The below sequence diagram displays the interactions while executing the command: setweak g/B
Save user data feature
Implementation
To make the application more user-friendly, we have implemented a feature which allows certain user data such as thresholdGrade
and the previous filter applied by the find
command to be saved in between sessions (i.e. after shutting down the application).
The main classes behind this feature are JsonUserDataStorage
, JsonSerializableUserData
and JsonAdaptedField
. The storage classes function much like the storage for the address book and archived book, while JsonAdaptedField
handles the user data, or fields, to be saved.
Given below is an example usage scenario for setting the weak threshold grade:
Step 1. The user executes setweak g/B
.
Step 2. The SetWeakThresholdCommand
object calls Grade#modifyThreshold(newThreshold)
, which in turn invokes JsonSerializableUserData#setGradeThreshold(newThreshold)
.
Step 3. As with the other storage classes, the new thresholdGrade
will be saved in the userdata.json
file automatically.
Step 4. The user shuts down the application.
Step 5. Upon relaunching, JsonUserDataStorage
will read the JSON file and update the relevant field to the saved value.
In the future, we hope to add more functionality to this feature, such as saving the preferred UI theme.
Summary Statistics Feature
Implementation
This is a new command to view summary statistics of all students.
Entering the command summary
results in a popup window in the GUI. The popup window consists of summary data including total
number of students, mean grade, and standard deviation of grades. Additionally, a colored pie chart is displayed of the
students’ grade distribution.
Given below is an example usage scenario:
Step 1. LogicManager
’s execute method calls the parseCommand
method from AddressBookParser
Step 2. parseCommand
creates a SummaryCommand
Step 3. SummaryCommand
’s execute method is called by LogicManager
.
Step 4. SummaryCommand
computes the total number of students, mean grade, and standard deviation of grade. It also generates
a pie chart of grades.
Step 5. SummaryCommand
creates and passes a CommandResult
object to LogicManager
Step 6. LogicManager
passes CommandResult
to UI
to display persons
list with the summary.
Currently, if the summary
command is used with 0 students, the popup window shows total number of students = 0, mean grade is blank,
and standard deviation as 0. And no pie chart is displayed.
Unlike other commands, the summary
command does not have a SummaryCommandParser
. This is because this command does not take in any input.
Proposed:
Modifying the summary command to include an input, thereby allowing the user to also view summary of a group.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- is an instructor for a CS-related course
- is organised and efficient
- prefers desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: keep track of the details of weaker students, allowing the instructor to pay more attention to them
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
Course Instructor who can type fast | enter new students’ information using command line | store the information efficiently |
* * * |
Course Instructor | put students into groups | tell which group each of the students are in |
* * * |
Course Instructor | access student’s contact information | communicate with them easily |
* * |
Course Instructor | delete student details on command line | remove students no longer in class |
* * * |
Seasoned Course Instructor | view a single student’s details | identify students of note |
* * |
Course Instructor | find all students in a specific group | focus on the students in the group |
* * |
Course Instructor | edit students’ info | update their info if it changes |
* * |
Course Instructor | view summary statistics for all students | |
* * |
Course Instructor | put a weak marker on students | identify which students have low grades |
* * |
Course Instructor | change the weak marker threshold | customize the weakness criteria |
Use cases
(For all use cases below, the System is the TeachStack
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Delete a student
MSS
- User requests to list students
- TeachStack shows a list of students
- User requests to delete a specific student in the list
-
TeachStack deletes the student
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given student id is invalid.
-
3a1. TeachStack displays an error message.
Use case resumes at step 2.
-
Use case: UC02 - Add a student
MSS
- User requests to add a student
-
TeachStack adds a new student to the list
Use case ends.
Extensions
- 1a. The value given for any parameter is invalid.
-
1a1. TeachStack displays an error message.
Use case ends.
-
Use case: UC03 - Form a group of students
MSS
- User requests to list students
- TeachStack shows a list of students
- User requests to group specific students in the list
-
TeachStack groups the student
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given student id is invalid.
-
3a1. TeachStack displays an error message.
Use case resumes at step 2.
-
Use case: UC04 - Setting weakness threshold
MSS
- User requests to set weakness threshold.
- TeachStack updates the weakness threshold grade.
-
TeachStack updates the display.
Use Case ends.
Extensions
- 1a. User requests weakness threshold be updated to an invalid grade.
-
1a1. TeachStack displays an error message.
Use Case ends.
-
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 students without a noticeable sluggishness in performance for typical usage.
- Should not lose data up to the latest operation in case of accidental close of application.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
Glossary
- API: An Application Programming Interface (API) is a set of rules, protocols and tools that allows different components to communicate with each other.
- Mainstream OS: Windows, Linux, Unix, MacOS
-
Details of student:
- Name: Name of the contact
- Student ID: Unique identifier of the contact
- Email: Unique email address of contact
- Grade: Letter grade of contact
- Group: Formation of multiple contacts
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.

Launch and shutdown
-
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 students. 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.
-
-
Saving weakness threshold preference
-
Use the
setweak
command to set a weak threshold other than the default C+. Close the window. -
Re-launch the app by double-clicking the jar file.
Expected: Students will be marked as weak according to the latest grade threshold set.
-
Editing a student
-
Editing a student’s id
-
Test case:
edit A0123458X id/A0123458T
Expected: Student with id: A0123458X now has id: A0123458T. Details of the edited student shown in the status message. -
Test case:
edit A0000000B id/A0123458T
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Test case:
edit A0123458X id/A0123456A
Expected: Student with id: A0123456A exists. Error details shown in the status message. Status bar remains the same. -
Test case:
edit A0123458X id/A0123456A id/A0123456Z
Expected: More than one student id specified. Error details shown in the status message. Status bar remains the same. -
Other incorrect edit commands to try:
edit
,edit x id/y
(where x, or y is not a valid student id),edit id/x
(where x can be a valid student id)
Expected: Similar to previous.
-
-
Editing a student’s email
-
Test case:
edit A0123458X e/e9876543@u.nus.edu
Expected: Student with id: A0123458X now has email: e9876543@u.nus.edu. Details of the edited student shown in the status message. -
Test case:
edit A0000000B e/e9876543@u.nus.edu
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Test case:
edit A0123458X e/e0654321@u.nus.edu
Expected: Student with email: e0654321@u.nus.edu exists. Error details shown in the status message. Status bar remains the same. -
Test case:
edit A0123458X e/e0654321@u.nus.edu e/e0654322@u.nus.edu
Expected: More than one email specified. Error details shown in the status message. Status bar remains the same. -
Other incorrect edit commands to try:
edit
,edit x e/y
(where x is not a valid student id, or y is not a valid email),edit e/x
(where x can be a valid email)
Expected: Similar to previous.
-
-
Editing a student’s group
-
Test case:
edit A0123458X gp/Group 1
Expected: Student with id: A0123458X now has group: Group 1. Details of the edited student shown in the status message. -
Test case:
edit A0123458X gp/Group 1 gp/Group 2
Expected: Student with id: A0123458X now has groups: Group 1, Group 2. Details of the edited student shown in the status message. -
Test case:
edit A0123458X gp/
Expected: Student with id: A0123458X no longer has any group. Details of the edited student shown in the status message. -
Test case:
edit A0000000B gp/Group 1
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Test case:
edit A0123458X gp/Group 1 gp/
Expected: Inconsistent command to clear groups and assign group. Error details shown in the status message. Status bar remains the same.- Other incorrect edit commands to try:
edit
,edit x g/y
(where x is not a valid student id, or y is not a valid group name),edit gp/x
(where x can be a valid group name)
Expected: Similar to previous.
- Other incorrect edit commands to try:
-
Deleting a student
-
Deleting a student while all students are being shown
-
Prerequisites: List all students using the
list
command. Multiple students in thepersons
list. -
Test case:
delete A0123458X
Expected: Student with id: A0123458X is deleted from the list. Details of the deleted student shown in the status message. -
Test case:
delete A0000000B
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
(where x is not a valid student id)
Expected: Similar to previous.
-
-
Deleting a student that is not being shown
-
Prerequisites: Find
Person
inGroup 20
using thefind gp/Group 20
command. Zero or more students in thepersons
list. -
Test case:
delete A0123458X
Expected: Student with id: A0123458X is deleted from the list. Details of the deleted student shown in the status message. -
Test case:
delete A0000000B
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
(where x is not a valid student id)
Expected: Similar to previous.
-
Grouping students
-
Grouping students
-
Prerequisites: Multiple students added to
persons
list. -
Test case:
group gp/Group 10 id/A0123458X
Expected: Student with id: A0123458X now has group: Group 10. Status message shown. -
Test case:
group gp/Group 10 id/A0123458X id/A0123456U
Expected: Student with id: A0123458X and student with id: A0123456U now have group: Group 10. Status message shown. -
Test case:
group gp/Group 10 gp/Group 11 id/A0123458X
Expected: Student with id: A0123458X now has groups: Group 10, Group 11. Status message shown. -
Test case:
group gp/ id/A0123458X
Expected: Student with id: A0123458X now has no group. Status message shown. -
Test case:
group gp/Group 10 id/A0123458X id/A0000000B
Expected: No student with id: A0000000B exists. Group command aborted. Error details shown in the status message. Status bar remains the same. -
Other incorrect group commands to try:
group
,group id/x
(where x can be a valid student id),group gp/z id/x id/y
(where x or y is an invalid student id, or z is an invalid group name)
Expected: Similar to previous.
-
Filtering the list by groups
-
Filtering a student using one group
-
Prerequisites: At least one student is in the group specified.
-
Test case:
group gp/Group 1
Expected: All students in Group 1 will be displayed. Status message shown.
-
-
Filtering a student using multiple groups
-
Prerequisites: At least one student is in the groups specified.
-
Test case:
group gp/Group 1 gp/Group 2
Expected: All students in both Group 1 and Group 2 will be displayed. Status message shown.
-
Archiving a student
-
Archiving a student while all students are being shown
-
Prerequisites: List all students using the
list
command. Multiple students in thepersons
list. -
Test case:
archive A0123458X
Expected: Student with id: A0123458X is moved frompersons
to thearchived
list. Details of the archived student shown in the status message. -
Test case:
archive A0000000B
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Other incorrect archive commands to try:
archive
,archive x
(where x is not a valid student id)
Expected: Similar to previous.
-
-
Archiving a student that is not being shown
-
Prerequisites: Find students in
Group 20
using thefind gp/Group 20
command. Zero or more students in thepersons
list. -
Test case:
archive A0123458X
Expected: Student with id: A0123458X is moved frompersons
to thearchived
list. Details of the archived student shown in the status message. -
Test case:
archive A0000000B
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Other incorrect archive commands to try:
archive
,archive x
(where x is not a valid student id)
Expected: Similar to previous.
-
Un-archiving a student
-
Un-archiving a student
-
Prerequisites: One or more students in the archived list.
-
Test case:
unarchived A0123458X
Expected: Student with id: A0123458X is moved from archived to thepersons
list. Details of the unarchived student shown in the status message. -
Test case:
unarchived A0123456A
Expected: No student with id: A0123456A exists in the archived list. Error details shown in the status message. Status bar remains the same. -
Test case:
unarchived A0000000B
Expected: No student with id: A0000000B exists. Error details shown in the status message. Status bar remains the same. -
Other incorrect unarchive commands to try:
unarchived
,unarchived x
(where x is not a valid student id)
Expected: Similar to previous.
-
Setting a grade threshold
-
Set grade threshold.
-
Test case:
setweak g/A
Expected: Update weakness threshold: A. Status message shown.Weak
marker appear next to name of all students with grade below or at A . -
Test case:
setweak A
Expected: Incorrect format. Error details shown in the status message. Status bar remains the same. -
Other incorrect setweak commands to try:
setweak
,setweak g/x
(where x is not a valid grade)
Expected: Similar to previous.
-
Saving data
-
Dealing with corrupted data files
-
Prerequisites: Folder named
data
exists in the same directory where the program is running, containing a file namedaddressbook.json
. Application is running. Delete the first line ofaddressbook.json
. -
Test case: Enter any successful command.
Expected: Running of application is not affected. -
Test case: Stop application. Rerun application.
Expected: Application starts with an emptypersons
list.
-
-
Dealing with missing data files
-
Prerequisites: Folder named
data
exists in the same directory where the program is running, containing a file namedarchivedbook.json
. Application is running and there is at least one student in archived list. Delete the filearchivedbook.json
. -
Test case: Enter any successful command.
Expected: Running of application is not affected. No loss of data, filearchived.json
appears indata
folder. -
Test case: Stop application. Rerun application.
Expected: Application starts with an empty archived list.
-
Viewing Summary
- View Summary
-
Test case: Enter
summary
with >0 students.
Expected: A popup window with a statistics component and pie chart. Status message with statistics shown. -
Test case: Enter
summary
with 0 students.
Expected: A popup window with a statistics (Total students = 0, Mean Grade = ‘’, Standard Deviation = 0.00) component. Status message with statistics.
-
Appendix: Planned Enhancements
Team Size: 5
- Ensure that the archive bar follows the UI theme, i.e. dark background in dark theme.
- Ensure that the summary statistics component follows the UI theme, i.e. dark background in dark theme.
- Provide ability to view archived students.
- Expand the characters accepted for name to include special characters like ‘s/o’ ,’-‘ etc.
- Allow for more strength indicators (weak, strong etc.) with threshold setting commands.
- Update the app to store multiple grades for a students. This allows users to track how students are performing and progressing and be able to display statistics for a student/group.
- Disable the minimize function of help window and re-centering help window when requested.
- Allow users to remove a group with a command. This will make it easier for users to create temporary groups which need to be cleared.
- Expand color scheme of summary window. This will make it grades easy to differentiate on the pie chart.
- Ensure aspects of UI (scrollbar, etc.) are clearly visible in both color themes, and minimized window.