Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Student
- Groups
- Tasks
- Help Window
- Saving data
- Effort
Acknowledgements
- Format of this DG is based on AB3 DG
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
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 has two classes called Main and MainApp. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons represents a collection of classes used by multiple other components.
The rest of the App consists of 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.
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 deleteStudent 1.

Each of the four main components (also shown in the diagram above),
- defines its API in an
interfacewith the same name as the Component. - implements its functionality using a concrete
{Component Name}Managerclass (which follows the corresponding APIinterfacementioned 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 multiple parts e.g.CommandBox, ListPanelPlaceholder, StatusBarFooter, HelpWindow etc. These parts, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
The XYZListPanel is in turn made up of other parts e.g. StudentListPanel, TaskListPanel, GroupListPanel.
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
Logiccomponent. - listens for changes to
Modeldata so that the UI can be updated with the modified data. - keeps a reference to the
Logiccomponent, because theUIrelies on theLogicto execute commands and to determine the type of object to display in theListPanelPlaceholder. - depends on some classes in the
Modelcomponent, as it displays either aStudent,Group, orTaskobject residing in theModel.
XYZListPanel Component
The XYZListPanel consists of either a StudentListPanel, TaskListPanel or GroupListPanel.
Each of these XYZListPanels consists of their own XYZCard components which make up the final GUI.
The layout of these XYZListPanels 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
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic component:

How the Logic component works:
- When
Logicis called upon to execute a command, it uses theAddressBookParserclass to parse the user command. - This results in a
Commandobject (more precisely, an object of one of its subclasses e.g.,AddStudentCommand) which is executed by theLogicManager. - The command can communicate with the
Modelwhen it is executed (e.g. to add a student). - The result of the command execution is encapsulated as a
CommandResultobject which is returned fromLogic.
The Sequence Diagram below illustrates the interactions within the Logic component for the execute("deleteStudent 1") API call.

DeleteStudentCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
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
AddressBookParserclass creates anXYZCommandParser(XYZis a placeholder for the specific command name e.g.,AddStudentCommandParser) which uses the other classes shown above to parse the user command and create aXYZCommandobject (e.g.,AddCommand) which theAddressBookParserreturns back as aCommandobject. - All
XYZCommandParserclasses (e.g.,AddStudentCommandParser,DeleteStudentCommandParser, …) inherit from theParserinterface 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
Student,GrouporTaskobjects (which are contained in aUniqueStudentList,UniqueGroupList,UniqueTaskListobject respectively). - stores the currently ‘selected’ objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable
ObservableList<>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
UserPrefobject that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPrefobjects. - does not depend on any of the other three components (as the
Modelrepresents data entities of the domain, they should make sense on their own without depending on other components)
The class diagrams of the Student, Task and Group classes are shown below:
Task Component

tApp allows TAs to manage their tasks for his or her professional or personal use.
The different types of lists include:
- Todo Tasks - Just a task to be completed in the future
- Deadline - A task to be completed in the future by a specified deadline
- Event - A task to be completed on a specified date
Common commands for the task model:
-
addTask- Creates a new task item -
editTask- Modifies an existing task -
deleteTask- Removes an existing task from the list of tasks -
markTask- Updates the status of a task item -
tasks- Shows all tasks in the list -
clearTasks- Removes all the tasks in the list
Rationale
The tApp is supposed to cater to TA, who are very busy. They have their own modules to prepare for and as well as prepare for weekly tutorial sessions. Hence, they have lots of things to keep track and a task manager feature is necessary. And there are primarily 3 types of tasks - todos, deadlines and events. tApp has supports all of these features to assist TAs in performing their tasks more efficiently and accurately.
Current Implementation
To adhere to Object-Oriented Programming principles, we have decided to make the Task class as an abstract parent class and TodoTasks, DeadlineTask and EventTask classes a subclass of Task class.
The Task class, and all its subclasses,
- stores information regarding a user’s task as shown above.
- stores a compulsory reference to a
TaskNameobject, aPriorityenumeration field, and a booleanisDonefield. - stores an optional reference to a
Descriptionobject. - stores
Tag, which is a class common to theStudentandGroupdata types.
In addition to the components above, the EventTask and DeadlineTask classes store a compulsory reference to a TaskDate object.
Student and Group Component

The Student component,
- stores the student’s personal information as shown by composition in the diagram above.
- stores
TagandRepoNamewhich are classes common to bothStudentandGroupdata types.RepoNamein this case refers to the name of the student’s IP repository. - stores a reference to the
Groupthe student is a part of via a uniquegroupNamefrom theGroupcomponent (composition is not valid here as aGroupcan exist with an emptyMembercomponent). This attribute is not modifiable via teh regulareditStudentcommand, and can only be modified internally when the student is added/deleted from aGroup, or theGroupNameof the student’s group changes.
The Group component,
- stores group related information, similarly shown by composition in the diagram above.
- stores
TagandRepoName. In this case,RepoNamerefers to the TP repository of the group. - has a
Memberssubcomponent that stores references to theStudentcomponent. This is initialized with no references to anyStudentto allow for preemptive creation of groups before members are made known.
Tag list in the AddressBook, which XYZ references. This allows AddressBook to only require one Tag object per unique tag, instead of each XYZ object 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 both
AddressBookStorageandUserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Modelcomponent (because theStoragecomponent’s job is to save/retrieve objects that belong to theModel)
Common classes
Classes used by multiple components are in the seedu.address.commons package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Find Command
The find command is generalised for two main groups of data in tApp: students and groups.
Implementation
Given below is an example usage scenario and how the find mechanism behaves at each step.
In this example, we explore the findStudent command.
The following diagram shows the workflow of a typical FindStudent command.

When the user executes the findStudent command, the user input is parsed to separate the command and its arguments. Special characters are removed during this parsing step. Students are then searched based on the specified arguments.
During the execution of FindStudentCommand, the student list will be filtered based on the predicate created from the arguments.
The following steps describes the execution of the FindStudent command, assuming no errors are encountered.
- The user executes a
findStudent alex bercommand to find students whose names contain the name wordalexorber. -
LogicManagerhandles this command by calling itsexecute(String)method. -
LogicManagerthen calls and passes this command toAddressBookParserto parse the command through itsparseCommand(String)method. - The
AddressBookParsercreates a newFindStudentCommandParserwhich will parse the argumentsparse(alex ber). This in turns create a newNameContainsKeywordPredicateinstance that checks if aStudentcontains the predicatesalexorber. - A new
FindStudentCommandis created byFindStudentCommandParserand is returned toLogicManagerwith the predicate as one of its fields. - The
LogicManagercalls theexecute()method inFindStudentCommand. - The
FindStudentCommandcalls theModel#updateFilteredStudentList()method, passing in the previously returned predicate as its argument. - The filtered student list is updated by checking all the students in the filtered students list with the
NameContainsKeywordPredicateinstance. - In this case, the filtered student list should return the students: Alex and Bernice as in the sample data.
- A new
CommandResultis returned, switching the current display to the filtered student list. The result is returned toLogicManager.
The above process is further summarised in the following sequence diagram:

FindStudentCommandParser, FindStudentCommand, NameContainsKeywordPredicate should end at the Destroy Marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Design Considerations
How can we improve search for a student?
-
Alternative 1 (selected implementation):
- Allow user to search through partial names. This is done through an
anyMatchusing any part of (contains)Stringpredicate. - Pros: Easier to implement, more convenient since there are no prefixes. Generally, this method results in a better user experience, since the user may not be exactly sure what the student name is if it is a complicated name.
- Cons: No search by different fields, e.g. email.
- Allow user to search through partial names. This is done through an
-
Alternative 2:
- Allow search of students through different fields with multiple prefixes.
- Pros: More freedom to find a student based on different fields.
- Cons: Increases complexity in software.
Mark Attendance/Participation/Task-as-Done Command
The mark command is generalised for two main groups of data in tApp: students and tasks.
These commands can be accessed through marka, markp for students, and doneTask for tasks.
Implementation
Given below is an example usage scenario and how the marking mechanism behaves at each step.
In this example, we explore the marka command.
- When the user executes the
markacommand, the user input is parsed to separate the command and its arguments. - The format of the command is first checked, followed by the checking and separation of the individual arguments (student index(es) and week). This is done in the
MarkStudentAttCommandParser#parse(String args)method. - The student’s attendance status for the particular week is retrieved and toggled. This operation is exposed in the
Modelinterface asModel#markStudentAttendance(Student student, int week). - If the student is originally marked as absent, the method toggles his attendance to present.
- If the student is originally marked as present, the method toggles his attendance to absent.
- If the student belongs to a group, the group’s student list will be updated with the updated student.
- Steps 3 to 6 are repeated for the next student, until all the specified students’ attendance are toggled.
- A new
CommandResultis returned, switching the current display to the updated student list. - Note: An error message will be thrown if: student index out of bounds, duplicate student index in the command, invalid week, invalid command format, invalid type of argument.
During the execution of MarkStudentAttCommand, the student list will be updated according to the arguments supplied.
The following diagram shows the summarised workflow of a typical marka command.

Design Considerations
How can we improve the marking of attendance of a student?
-
Alternative 1 (selected implementation):
- Toggle the attendance when the
markacommand is executed for the student. - Pros: More intuitive for the user, just call the command to mark the attendance. Easier to implement, more convenient since there are no prefixes/flags.
- Cons: May accidentally mark the attendance wrongly (e.g. present to absent).
- Toggle the attendance when the
-
Alternative 2:
- Use of flags
-p(present),-a(absent) to mark attendance - Pros: Less confusing for the user when there is a larger set of students (>100). Lesser risk of mis-marking a user.
- Cons: Increases complexity, more flags for user to remember.
- Use of flags
Add Member to Group Command
The add member command can be executed to form an association between two main data types in tApp, Groups and Students.
Implementation

As with all other commands in tApp, the addMember feature is activated when a user enters the addMember command word followed by its relevant arguments.
The main difference between the addMember command lies not in the way the Logic class is activated but in the way the Model class processes this command.
When the user executes the addMember command, user input is parsed and the Index of student to be added, and the GroupName of the group to be added to are extracted into parameters of the AddMemberCommand class.
If any errors are present in the user input, exceptions are thrown in the following components, summarised in the following activity diagram:

-
AddMemberCommandParserthrows an exception if command format is invalid (negative/missing index, missing group prefix) -
AddMemberCommandthrows an exception if theIndexdoes not exist in the student list,GroupNameis does not belong to any preexistingGroup. It also throws an exception if the student is already in another group, or the student has already been added to the current group. The workflow for throwing these exceptions is similar to the first two and is not shown in the activity diagram below.
The interaction between the Logic and Model classes are shown in the following sequence diagram:

A key difference to note about this command is that it gets a list of both Students and Groups from models, instead of only 1 list as per other commands.
The follow steps describes the execution of the AddMember command:
-
AddMemberCommanduses the providedIndexandGroupNameto obtain both a reference to theStudent(usingIndex) and theGroup(usingGroupName). SinceGroupNameis unique, there will only be oneGroupselected. -
AddMemberCommandthen uses these references to call theaddMembersfunction of theModelclass. - The
Modelthen creates and stores a newStudentusing the same information as theStudentparameter passed in, but substituting theGroupNamefield to the name of theGrouppassed as a parameter. -
Modelthen calls theaddMemberfunction of the referencedGroup, passing in the newly createdStudentas a parameter. -
Groupthen calls theaddMemberfunction of itsMemberclass, passing in the sameStudentparameter. - The
Memberthen stores a reference to thisStudent. -
Modelthen callssetStudentandsetGroupto update these changes inAddressBook. - Execution of this command then follows the usual execution path of all other commands in tApp.
Unlike other commands which only changes itself in the Model class, addMembers updates both the Student to be added and the Group to which the student is added to, and saves both these changes in the AddressBook.
Design considerations:
- Alternative 1 (selected implementation): Have
Memberssave a list ofStudentandStudenthave a reference toGroupName- Pros: Easy to implement, all relevant student information can be readily accessed and displayed in the GUI.
- Cons: Increases coupling between
StudentandGroupclasses.
- Alternative 2: Have
Memberssave theNameof students andStudenthave a reference toGroup- Pros: Smaller JSON file size due to smaller volume of information being referenced to.
- Cons: Increases coupling between
StudentandGroupclasses, need to find the relevantStudentobject given itsNameeverytime theGroupis to be displayed in the GUI, unnatural modelling of the real world sinceGroupcontains students and not the other way around.
- Alternative 3: Have
Memberssave theNameof students only- Pros: Smaller JSON file size due to smaller volume of information being referenced to, lesser coupling due to only a unidirectional association.
- Cons: Unable to display the
GroupNameof aStudentin the student display list using simple code implementation, reduction in input validation capabilities (assigning 1 student to 2 groups) since there is no direct way to determine if aStudentis already in a group.
Edit Group Command
Implementation

The Edit Group feature is activated when a user enters the editGroup command word followed by its relevant arguments.
When the user executes the editGroup command, user input is parsed and the fields to be edited are extracted into an EditGroupDescriptor object.
The EditGroupDescriptor object and the Index of the group to be edited are then extracted into parameters of the EditGroupCommand class.
The EditGroupCommand then interacts with the Model class to edit the data.
The implementations of the other Edit commands, namely the EditTaskCommand and the EditStudentCommand, are similar to the EditGroupCommand in the way the Logic component behaves.
However, the behaviour of the Model component differs slightly for the EditGroupCommand, as it alters not only the Group data, but also the Student data in the AddressBook.
This process is shown in the following sequence diagram:

The following steps describe the execution of the EditGroupCommand.
-
EditGroupCommanduses the providedIndexandEditGroupDescriptorto create the updatedGroupobject. -
EditGroupCommandcalls thesetGroupmethod of theModelclass to replace the previousGroupobject with the newly updated one. -
Modelthen updates allStudentobjects that are part of theMembersclass of the group. This is achieved by creating newStudentobjects that have a reference to theGroupNameof the updated group, and calling thesetStudentmethod ofAddressBookto update theStudent data. - Finally,
Modelcalls thesetGroupfunction of theAddressBookto update theGroupdata of theAddressBook.
Edit Task Command
Implementation

The Edit Task feature is activated when a user enters the editTask command word followed by its relevant arguments.
When the user executes the editTask command, user input is parsed and the fields to be edited are extracted into an EditTaskDescriptor object.
The EditTaskDescriptor object and the Index of the task to be edited are then extracted into parameters of the EditTaskCommand class.
The EditTaskCommand then interacts with the Model class to edit the data.
The implementations of the other Edit commands, namely the EditGroupCommand and the EditStudentCommand, are similar to the EditTaskCommand in the way the Logic component behaves.
However, the behaviour of the Model component differs slightly for the EditTaskCommand, as it alters only the Task data in the AddressBook.
This process is shown in the following sequence diagram:

The following steps describe the execution of the EditTaskCommand.
-
EditTaskCommanduses the providedIndexandEditTaskDescriptorto create the updatedTaskobject. -
EditTaskCommandthen calls thesetTaskmethod of theModelclass to replace the previousTaskobject with the newly updated one. - Finally,
Modelcalls thesetTaskfunction of theAddressBookto update theTaskdata.
Adding Todo Task
Given below is an example usage scenario of adding a todo task and how the adding a todo task mechanism behaves at each step.
- The user executes the
todo n/Complete tp p/H t/CS2103 t/Workto add a Todo Task named ‘Complete tp’ with the tags ‘CS2103’ and ‘Work’ to the list of tasks and marks this task as High Priority. - The command is handled by
LogicManager#execute(String), which then calls and passes this command to theAddressBookParser#parseCommand(String)method. - The
AddressBookParserdetects the command wordtodoin the string and extracts the argument stringn/Complete tp p/H t/CS2103 t/Work. - The
AddressBookParsercreates a newAddTodoTaskCommandParserinstance to parse the argument string according to the format specified forAddTodoTaskCommand. - The argument string is parsed to create new tags and keep them in a
Set<Tags>and the Priority of the task is set to high. These are done using theAddTodoTaskCommandParser#parse(String)method, which also performs validation. - The
AddTodoTaskCommandParsercreates a newAddTodoTaskCommandand returns it to AddressBookParser, which in turn returns it toLogicManager. - The LogicManager calls the
AddTodoTaskCommand#execute(Model)method. - The AddTodoTaskCommand calls the
Model#addTask(Task)method. - The task is added to the list of tasks and the updated list of task is displayed.
- Lastly, the
AddTodoTaskCommandcreates aCommandResultwith a success message and returns it toLogicManager.
The above process is shown in the following sequence diagram:

Sequence diagram showcasing the add todo task process
AddTodoTaskCommandParser 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 new command to find the members by keywords:

Activity diagram showcasing the add todo task execution flow
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
This product is for CS2103/T TAs who are:
- Familiar with command line and code
- Worried about using too many applications to manage his students’ projects and grades.
- Able to tolerate a steep learning curve
- Disorganized, forgetful
- Busy with other school projects and modules
Value proposition:
TAs are required to complete different tasks (mark attendance and participation, track tp progress) and manage multiple groups and students.
This application aims to integrate different tasks into a centralised platform that can improve a TA’s efficiency. It helps to ensure instructors complete all tasks by stipulated deadlines.
User stories
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 task with time | be reminded of when certain tasks are due |
* * * |
user | delete tasks | not be cluttered with completed/wrong tasks |
* * * |
user | mark students’ attendance | keep track of who is present |
* * * |
user | mark tasks as complete | know which tasks have already been done |
* * * |
user | view my todo list | know what tasks I have to do |
* * * |
user | view my student list | know what students I have |
* * * |
user | view my groups list | know what groups I have |
* * * |
user | add a student | add my student into the list |
* * * |
user | delete a student | remove my student if he quits the course |
* * * |
user | add a group | add a group into the list |
* * * |
user | delete a group | remove a group if I am not in charge of them anymore |
* * * |
user | store my data in a file | easily export data from the application |
* * * |
user | add GitHub links for each student | easily access their Github to check their progress |
* * * |
user | add GitHub links for each student group | easily access their Github to check their progress |
* * * |
user | record attendance during tutorials | accurately award attendance marks to students |
* * * |
user | record participation during tutorials | accurately award participation marks to students |
* * * |
user | add descriptions to the tasks | see the extra detail pertaining to the task |
* * |
user | set my current directory to either students or tasks or groups | add students/tasks/groups more easily |
* * |
user | access the ‘help’ page with all available commands | refer to instructions when I forget how to use tApp |
* * |
user | add students as members to different groups | Keep track of different group members and their progress |
* * |
user | delete student members from groups | remove members if they quit their course or change their groups |
* * |
user | edit groups | correct any errors I made without deleting and creating a new group |
* * |
user | edit tasks | correct any errors I made without deleting and creating a new task |
* * |
user | edit students | correct any errors I made without deleting and creating a new student |
* * |
user | search for a student | quickly access all information related to the student |
* * |
user | search for a group | quickly access all information related to the group |
* * |
user | purge all current students | start a new semester with new students |
* * |
user | purge all current groups | start a new semester with new groups |
* * |
user | purge all current tasks | get rid of all my tasks |
* * |
user | purge all current data | get rid of sample data I used for exploring the app |
* * |
expert user | sort tasks by earliest deadline | know what tasks need to be completed urgently |
* * |
user | assign priority levels for tasks | know what tasks require my earliest attention |
* * |
user | create events as a type of task | keep track of tasks that occur at a specified time |
* * |
user | create tags to be added to tasks | easily access the links related to the task |
* |
user | sort groups & students by their tP / iP progress | see who needs help |
* |
user | tag students to specific tasks | keep track of students related to a task |
* |
user | specify default tasks to add when adding students | I do not need to manually add the same tasks |
* |
expert user | view the changes I made to my todo list | recover tasks that are accidentally deleted |
* |
user | set automated reminders upon startup | not forget any task |
* |
expert user | create command line shortcuts to access tasks | easily access data and save time |
* |
user | set recurring tasks | not create tasks that I have to complete regularly |
* |
user | customise the order of the menu | easily access the features I use most |
* |
user | broadcasts task to a certain group | efficiently add new module wide tasks |
* |
user | string multiple commands into a single line | manage my tasks more efficiently |
* |
user | view both my students’ tasks and my own tasks | be informed of the week’s progress |
* |
expert user | create custom commands | make managing tasks more convenient, and more tailored to my needs |
* |
user | filter the CS2103/T textbook | refresh my memory on concepts I forgot |
* |
user | import data from CSV files | get started with the app quickly |
Use cases
(For all use cases below, the System is tApp and the Actor is the user, unless specified otherwise)
Use case: UC1 - View student list
MSS
- User requests to list all students
-
tApp displays the list of students
Use case ends.
Extensions
-
1a. Full student list is already displayed.
Use case ends.
-
2a. The list is empty.
Use case ends.
Use case: UC2 - Add a student
MSS
- User requests to view students (UC1)
- tApp displays the list of students
- User requests to add a student
-
tApp adds the student
Use case ends.
Extensions
-
3a. No name is specified.
-
3a1. tApp shows an error message.
Use case ends.
-
Use case: UC3 - Edit a student
MSS
- User requests to view students (UC1)
- tApp displays the list of students
- User requests to edit a specific student in the list by specifying the details to edit
-
tApp edits the student details
Use case ends.
Extensions
-
2a. The student list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. tApp shows an error message.
Use case ends.
-
Use case: UC4 - Delete a student
Similar to UC3, except we are deleting a student and there is no need to edit the student details.
Use case: UC5 - Mark student as present
MSS
- User requests to view students (UC1)
- tApp lists all students
- User requests to mark a specific student as present in the list
-
tApp marks the student as present
Use case ends.
Extensions
-
2a. The student list is empty.
Use case ends.
-
2b. User requests to mark a specific student as absent in the list.
-
2b1. tApp marks the student as absent.
Use case ends.
-
-
3a. The given index is invalid.
-
3a1. tApp shows an error message.
Use case ends.
-
Use case: UC6 - Mark student as participated
Similar to UC5, except the student’s participation is marked instead of attendance.
Use case: UC7 - Find student by name
MSS
- User requests to find student whose name is John
-
tApp displays all names containing ‘john’
Use case ends.
Extensions
-
2a. The student list is empty.
-
2a1. tApp displays an empty list
Use case ends.
-
Use case: UC8 - Clear student list
MSS
- User requests to view students (UC1)
- tApp displays the list of students
- User requests clear the student list
-
tApp clears the student list
Use case ends.
Extensions
-
2a. The student list is empty.
Use case ends.
Use case: UC9 - View group list
MSS
- User requests to view the list of groups
-
tApp displays all groups
Use case ends.
Extensions
-
1a. Full group list is already displayed.
Use case ends.
-
2a. The group list is empty.
-
2a1. tApp displays an empty list
Use case ends.
-
Use case: UC10 - Add a group
MSS
- User requests to create a group with the specified name
- tApp creates the group and stores it in the group list
-
tApp displays all groups
Use case ends.
Extensions
-
1a. The group name is empty or invalid.
-
1a1. tApp displays an error message stating that the group name is invalid
Use case ends.
-
Use case: UC11 - Edit a group
MSS
- User requests to view the list of groups
- tApp displays all groups
- User requests to edit a specific group from the list of groups
- tApp edits the group
-
tApp displays all groups with the edited group
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. tApp shows an error message.
Use case ends.
-
Use case: UC12 - Delete a group
Similar to UC11 (Edit a group), except the group is deleted instead of edited.
Use case: UC13 - Add a student to group
MSS
- User requests to view the list of students
- tApp displays all the students
- User requests to add a specific student from the list of students to a specific group from the list of groups
-
tApp adds the student to the group
Use case ends.
Extensions
-
3a. The group name is empty or invalid.
-
3a1. tApp displays an error message stating that the group name is invalid.
Use case ends.
-
-
3b. The student index is empty or invalid.
-
3b1. tApp displays an error message stating that the command format is invalid.
Use case ends.
-
Use case: UC14 - Delete student from group
Similar to UC13 (Add student to group), except we are deleting the student from the group, and group index and member list index is used instead of group name and student list index.
Use case: UC15 - Find groups by name
Similar to UC7 (Find student by name), except we are finding groups by group name.
Use case: UC16 - Clear group list
Similar to UC8 (Clear student list), except we are clearing the group list.
Use case: UC17 - View task list
MSS
- User requests to view the list of tasks
-
tApp displays all tasks
Use case ends.
Extensions
-
1a. Full task list is already displayed.
Use case ends.
-
2a. The task list is empty.
Use case ends.
Use case: UC18 - Add a todo task
MSS
- User requests to create a todo task
- tApp creates the todo and stores it in the task list
-
tApp displays the task list with the task that was just created
Use case ends.
Extensions
-
1a. The task name is empty.
-
1a1. tApp displays an error message stating that the task name is invalid
Use case ends.
-
-
1b. The command format is incorrect.
-
1b1. tApp displays an error message requesting the user to follow the correct format
Use case ends.
-
Use case: UC19 - Add a task with a specified deadline
MSS
- User requests to create a task with a specified deadline
- tApp creates the task and stores it in the task list
-
tApp displays the task list with the task that was just created
Use case ends.
Extensions
-
1a. The task name is empty.
-
1a1. tApp displays an error message stating that the task name is invalid
Use case ends.
-
-
1b. The format of the deadline is incorrect.
-
1b1. tApp displays an error message requesting the user to follow the correct deadline format
Use case ends.
-
Use case: UC20 - Add a task with a specified event date
Similar to UC19 (Add a task with a specified deadline), except the deadline is an event date.
Use case: UC21 - Edit a task
MSS
- User requests to view the list of tasks
- tApp displays all the tasks currently in the list
- User requests to edit a specific task from the list of tasks
- tApp edits the task
-
tApp displays the task list
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. tApp shows an error message.
Use case ends.
-
Use case: UC22 - Delete a task
Similar to UC21 (Edit a task), except the task is deleted instead of edited.
Use case: UC23 - Mark a task as done
Similar to UC21 (Edit a task), except the task is marked as done instead of edited.
Use case: UC24 - Clear task list
Similar to UC8 (Clear student list), except we are clearing the task list.
Use case: UC25 - Clear all entries in tApp
Similar to UC8 (Clear student list), except we are clearing the whole address book.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11or above installed. - Should be able to hold up to 100 students without a noticeable sluggishness in performance for typical usage.
- 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.
- Commands used should be intuitive, and should not exceed 80 characters.
- System should respond almost immediately (max: 3 seconds) upon entering a command.
- Error messages shown should inform the user of what is wrong and what the correct command syntax should be.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Student: A student contact.
- Group: A CS2103 group consisting of multiple members, which are student contacts.
- Task: A todo task, a deadline task (task with a deadline) or an event task (task with an event date).
- Directory: The list of students, groups or tasks.
-
Invalid: An input is invalid when it does not follow the correct command input format. Inputs are also invalid if executing a command with that input would result in duplicate data items (
Student,Group, orTask) in the application.
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, tasks and groups. 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.
-
Student
Adding a student
-
Adding a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
addStudent n/John Doe e/john@u.nus.edu s/a0000001b u/johndoee r/ip
Expected: A student is added to the bottom of the list, with GitHub link shown. Details of the student is shown in the status message. Letters in student number are automatically capitalized. -
Test case:
addStudent n/John Doe e/jondoe@u.nus.edu s/a0000002b u/jondoee r/ip
Expected: Similar to previous, no error thrown, student with same name added. -
Test case:
addStudent n/Mary Doe e/mary@u.nus.edu s/a0000001bor any other student with conflicting student number or email
Expected: No student is added. Error message of duplicate student shown in status message. -
Test case:
addStudentwith missingn/,e/, and/ors/prefixes
Expected: No student is added. Error message of invalid command format shown.
-
-
Adding a student while on another directory
-
Prerequisites: List all tasks or groups using the
tasksorgroupscommand. -
Perform a successful
addStudentcommand Expected: A student is added, and the student list is displayed.
-
Deleting a student
-
Deleting a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
deleteStudent 1
Expected: First student is deleted from the list. Details of the deleted student shown in the status message. -
Test case:
deleteStudent 0
Expected: No student is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
deleteStudent,deleteStudent x,deleteStudent 1 2 3(where x is larger than the list size)
Expected: Similar to previous.
-
Editing a student
-
Editing a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
editStudent 1 n/John Doe u/johndoee r/ip
Expected: The first student in the list has details changed to the ones specified above. Details of the student is shown in the status message. -
Test case:
editStudent 1 s/a0000001bor any other student number or email or both to that conflicts with another student in the list
Expected: No student is edited. Error message of duplicate student shown in status message. -
Test case:
editStudent 999 n/testwhere the index is greater than the number of students in the list.
Expected: No student is edited. Error message invalid index shown. -
Test case:
editStudent 1with no prefixes
Expected: No student is edited. Error message of missing edit fields shown. -
Test case:
editStudent 0 n/test, where the index is 0 or smaller
Expected: No student is edited. Error message of invalid command format shown.
-
-
Editing a student while on another directory
-
Prerequisites: List all tasks or groups using the
tasksorgroupscommand. -
Perform a successful
editStudentcommand Expected: The student is edited, and the student list is displayed.
-
Marking a student’s attendance
-
Marking a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
marka 1 w/4
Expected: First student is marked as present in the list. Status message shows details of his week 4 attendance. -
Test case:
marka 0 w/4
Expected: No student is marked. Error details shown in the status message. -
Other incorrect mark attendance commands to try:
marka,marka x,...(where x is larger than the list size)
Expected: Similar to previous.
-
-
Marking a student while on another directory
-
Prerequisites: Perform a
findStudentcommand: e.g.findStudent David. -
Test case:
marka 1 w/5
Expected: First student in the last filtered students list (David) is marked as present. Status message shows details of student’s week 1 attendance. Updated students list is shown. -
Test case:
marka 1 w/5
Expected: First student in student list (Alex) is marked as present/absent depending on his last attendance status. Status message shows details of student’s week 1 attendance. Updated students list is shown.
-
-
Marking multiple students
-
Test case:
marka 1 2 3 w/4
Expected: Students 1, 2 and 3 are marked as present in the list. Status message shows details of their week 4 attendance. -
Test case:
marka 1 2 3 w/4
Expected: Students 1, 2 and 3 are marked as absent in the list. Status message shows details of their week 4 attendance.
-
Marking a student’s participation
-
Marking a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
markp 1 w/3
Expected: First student is marked as participated in the list. Status message shows details of his week 3 participation. -
Test case:
markp 0 w/3
Expected: No student is marked. Error details shown in the status message. -
Other incorrect mark participation commands to try:
markp,markp x,...(where x is larger than the list size)
Expected: Similar to previous.
-
-
Marking a student while on another directory
-
Prerequisites: Perform a
findStudentcommand: e.g.findStudent David. -
Test case:
markp 1 w/3
Expected: First student in the last filtered students list (David) is marked as participated. Status message shows details of student’s week 3 participation. Updated students list is shown. -
Test case:
markp 1 w/3
Expected: First student in student list (Alex) is marked as participated/not participated depending on his last participation status. Status message shows details of student’s week 3 participation. Updated students list is shown.
-
-
Marking multiple students
-
Test case:
markp 1 2 3 w/3
Expected: Students 1, 2 and 3 are marked as participated in the list. Status message shows details of their week 3 participation. -
Test case:
markp 1 2 3 w/3
Expected: Students 1, 2 and 3 are marked as not participated in the list. Status message shows details of their week 3 participation.
-
Finding a student
-
Finding a student while all students are being shown
-
Prerequisites: List all students using the
studentscommand. Multiple students in the list. -
Test case:
findStudent al
Expected: Students whose name contains “al” will be shown (e.g. Alex). Status message shows how many students has been found. -
Test case:
findStudent !alex! ben123
Expected: Students whose name contains “alex” OR “ben” will be shown (e.g. Alex, Ben). Special characters and numbers ignored. Status message shows how many students has been found. -
Other incorrect findStudent commands to try:
findStudent,findStudent !
Expected: No student found. Error details shown in the status message.
-
-
Finding a student while in another directory
Expected: Similar to previous.
Clearing student list
-
Clearing the student list
- Test case:
clearStudents
Expected: All students cleared from student list. Existing students in groups will also be cleared, leaving empty groups.
- Test case:
Groups
Adding a group
-
Adding a group while all groups are being shown
-
Prerequisites: List all groups using the
groupscommand. Multiple groups in the list. -
Test case:
addGroup g/w14-4 y/AY2122S1 r/tp
Expected: A group is added to the bottom of the list, with GitHub link shown. Details of the group is shown in the status message. Letter in group name is automatically capitalized. -
Test case:
addGroup g/w14-4or any other group with conflicting name
Expected: No group is added. Error message of duplicate group shown in status message. -
Test case:
addGroupwith missingg/prefixes (other prefixes can be present)
Expected: No student is added. Error message of invalid command format shown.
-
-
Adding a group while on another directory
-
Prerequisites: List all tasks or students using the
tasksorstudentscommand. -
Perform a successful
addGroupcommand Expected: A group is added, and the group list is displayed.
-
Deleting a group
-
Deleting a group while all groups are being shown
-
Prerequisites: List all groups using the
groupscommand. Multiple groups in the list. -
Test case:
deleteGroup 1
Expected: First group is deleted from the list. Details of the deleted group shown in the status message. Members of the group in student list are no longer tagged to the group. -
Test case:
deleteGroup 999where the index of the group is greater than the size of the group list
Expected: No group is deleted. Error message of invalid index shown in the status message. -
Test case:
deleteGroup 0
Expected: No group is deleted. Error message of invalid command format shown in the status message. -
Other incorrect delete commands to try:
deleteGroup,deleteGroup x,...(where x is smaller than 0)
Expected: Similar to previous.
-
Editing a group
-
Editing a group while all groups are being shown
-
Prerequisites: List all groups using the
groupscommand. Multiple groups in the list. -
Test case:
editGroup 1 r/ip
Expected: The first group in the list has details changed to the ones specified above. Details of the group is shown in the status message. -
Test case:
editGroup 1 g/w14-4changing group name a value conflicting another group in the list
Expected: No group is edited. Error message of duplicate group shown in status message. -
Test case:
editGroup 999 g/z11-1where the index is greater than the number of groups in the list.
Expected: No group is edited. Error message invalid index shown. -
Test case:
editGroup 1with no prefixes
Expected: No group is edited. Error message of missing edit fields shown. -
Test case:
editGroup 0 g/z11-1, where the index is 0 or smaller
Expected: No group is edited. Error message of invalid command format shown.
-
-
Editing a group while on another directory
-
Prerequisites: List all tasks or students using the
tasksorstudentscommand. -
Perform a successful
editGroupcommand Expected: The group is edited, and the group list is displayed.
-
Adding a group member
-
Adding a group member while all groups are being shown
-
Prerequisites: List all groups using the groups command. Multiple groups in the list. Student to be added to the group does not belong to any group.
-
Test case:
addMember 1 g/w14-4where a group with the name of W14-4 exists
Expected: First student in the student list is added to group W14-4 as a member. Success message shown in the status message. Student in student list is tagged to the group. -
Test case:
addMember 999 g/w14-4where the index of the student is greater than the size of the student list
Expected: No member is added. Error message of invalid index shown in the status message. -
Test case:
addMember 2 g/z11-1where no group with name Z11-1 exists
Expected: No member is added. Error message of invalid group name shown in the status message. -
Test case:
addMember 0 g/w14-4
Expected: No group is added. Error message of invalid command format shown in the status message. -
Other incorrect delete commands to try:
addMember,addMember x g/w14-4,...(where x is smaller than 0)
Expected: Similar to previous.
-
Deleting a group member
-
Deleting a group member while all groups are being shown
-
Prerequisites: List all groups using the
groupscommand. Multiple groups in the list. -
Test case:
deleteMember 1 1where the first group has at least 1 member
Expected: First student in the member list of the first group in the group list is deleted. Success message shown in the status message. Student in student list is no longer tagged to the group. -
Test case:
deleteMember 999 1where the index of the group is greater than the size of the group list
Expected: No member is deleted. Error message of invalid group index shown in the status message. -
Test case:
deleteMember 1 99where the index of the member is greater than the size of the member list exists
Expected: No member is deleted. Error message of invalid member index shown in the status message. -
Test case:
deleteMember 0 1
Expected: No member is deleted. Error message of invalid command format shown in the status message. -
Other incorrect delete commands to try:
deleteMember,deleteMember x y,...(where x and/or y are smaller than 0)
Expected: Similar to previous.
-
Finding a group
-
Finding a group while all groups are being shown
-
Prerequisites: List all groups using the
groupscommand. Multiple groups in the list. -
Test case:
findGroup w14
Expected: Groups whose name contains “w14” will be shown (e.g. W14-4). Case-insensitive. Status message shows how many groups has been found. -
Test case:
findGroup w14 w15-2
Expected: Groups whose name contains “w14” OR “w15-2” will be shown (e.g. W14-2, W14-4, W15-2). Ignores all special characters except dashes. Case-insensitive. Status message shows how many groups has been found. -
Other incorrect findGroup commands to try:
findGroup,findGroup !
Expected: No groups found. Error details shown in the status message.
-
-
Finding a group while in another directory
Expected: Similar to previous.
Clearing group list
-
Clearing the group list
- Test case:
clearGroups
Expected: All groups cleared from group list. Existing students in groups will be removed from their group (students will have no group).
- Test case:
Tasks
Adding a todo task
-
Adding a todo task while all tasks are being shown.
-
Prerequisites: List all groups using the
taskscommand. Multiple tasks in the list. -
Test case:
todo n/Prepare for Tutorial
Expected: Creates a new todo task named “Prepare for Tutorial”, adds it to the list of tasks and displays all the tasks. -
Test case:
todo n/Prepare for Tutorial by/2021-11-01
Expected: No new todo task created. Error details shown in the status message. -
Other incorrect findGroup commands to try:
todo,todo !
Expected: No new todo task created. Error details shown in the status message.
-
-
Adding a todo task while in another directory
Expected: Similar to previous.
Adding a deadline task
-
Adding a deadline task while all tasks are being shown.
-
Prerequisites: List all groups using the
taskscommand. Multiple tasks in the list. -
Test case:
deadline n/Prepare for Tutorial by/2021-11-01
Expected: Creates a new deadline task named “Prepare for Tutorial” with a deadline “2021-11-01”, and adds it to the list of tasks and displays all the tasks. -
Test case:
deadline n/Prepare for Tutorial
Expected: No new deadline task created. Error details shown in the status message. -
Other incorrect findGroup commands to try:
deadline n/Prepare for Tutorial on/2021-11-01,deadline,deadline !
Expected: No new todo task created. Error details shown in the status message.
-
-
Adding a deadline task while in another directory
Expected: Similar to previous.
Adding an event task
-
Adding an event task while all tasks are being shown.
-
Prerequisites: List all groups using the
taskscommand. Multiple tasks in the list. -
Test case:
event n/Conduct Tutorial on/2021-11-01
Expected: Creates a new deadline task named “Conduct Tutorial” on “2021-11-01”, and adds it to the list of tasks and displays all the tasks. -
Test case:
event n/Conduct Tutorial
Expected: No new deadline task created. Error details shown in the status message. -
Other incorrect findGroup commands to try:
event n/Conduct Tutorial by/2021-11-01,event,event !
Expected: No new todo task created. Error details shown in the status message.
-
-
Adding an event task while in another directory
Expected: Similar to previous.
Editing a task
-
Editing a task while all tasks are being shown
-
Prerequisites: List all tasks using the
taskscommand. Multiple tasks in the list. -
Test case:
editTask 1 n/Tutorial p/high d/Covers important topics for finals.
Expected: The first task in the list has details changed to the ones specified above. Details of the task is shown in the status message. -
Test case:
editTask 999 n/testwhere the index is greater than the number of tasks in the list.
Expected: No task is edited. Error message invalid index shown. -
Test case:
editTask 1with no prefixes
Expected: No task is edited. Error message of missing edit fields shown. -
Test case:
editTask 0 n/test, where the index is 0 or smaller
Expected: No task is edited. Error message of invalid command format shown.
-
-
Editing a task while on another directory
-
Prerequisites: List all students or groups using the
studentsorgroupscommand. -
Perform a successful
editTaskcommand Expected: The task is edited, and the task list is displayed.
-
-
Editing a deadline task
-
Prerequisites: There must be at least one Deadline Task present in the task list.
-
Test Case:
editTask 1 by/2021-12-12, where the index is the index of the deadline task
Expected: The Deadline Task is edited. Details of the task is shown in the status message. -
Test Case:
editTask 1 on/2021-12-12, where the index is the index of the deadline task
Expected: No task is edited. Error message of invalid prefix is shown. -
Test Case:
editTask 1 by/2021-20-12, where the date provided is invalid.
Expected: No task is edited. Error message of invalid date shown.
-
-
Editing an event task
-
Prerequisites: There must be at least one Event Task present in the task list.
-
Test Case:
editTask 1 on/2021-12-12, where the index is the index of the event task
Expected: The Event Task is edited. Details of the task is shown in the status message. -
Test Case:
editTask 1 by/2021-12-12, where the index is the index of the event task
Expected: No task is edited. Error message of invalid prefix is shown. -
Test Case:
editTask 1 on/2021-20-12, where the date provided is invalid.
Expected: No task is edited. Error message of invalid date shown.
-
-
Editing a todo task
-
Prerequisites: There must be at least one Todo Task present in the task list.
-
Test Case:
editTask 1 by/2021-12-12, where the index is the index of the todo task
Expected: No task is edited. Error message of invalid prefix is shown. -
Test Case:
editTask 1 on/2021-12-12, where the index is the index of the todo task
Expected: No task is edited. Error message of invalid prefix is shown.
-
Deleting a task
-
Deleting a tasks while all tasks are being shown
-
Prerequisites: List all tasks using the
taskscommand. Multiple tasks in the list. -
Test case:
deleteTask 1
Expected: First tasks is deleted from the list. Details of the deleted task shown in the status message. -
Test case:
deleteTask 0
Expected: No task is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
deleteTask,deleteTask x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Marking a task as done
-
Marking a task as done while all tasks are being shown
-
Prerequisites: List all tasks using the
taskscommand. Multiple tasks in the list. -
Test case:
doneTask 1
Expected: First task is marked as completed. Status message shows details of the task. -
Test case:
doneTask 0
Expected: No task is marked. Error details shown in the status message. -
Other incorrect mark task commands to try:
doneTask,doneTask x,...(where x is larger than the list size)
Expected: Similar to previous.
-
-
Marking a task as done while on another directory
-
Prerequisites: Go to another directory, either by executing the
groupsorstudentscommands, or performing a command that brings you to another directory (e.gfindStudentcommand:findStudent David). -
Test case:
doneTask 1
Expected: First task in the last filtered task list is marked as complete. Status message shows details of tasks. Updated task list is shown.
-
-
Marking multiple tasks
- Test case:
doneTask 1 2 3
Expected: Tasks 1, 2 and 3 are marked as completed in the list. Status message shows details of tasks.
- Test case:
Clearing task list
-
Clearing the tasks list
- Test case:
clearTasks
Expected: All tasks cleared from task list.
- Test case:
Clearing all data from tApp
-
Clearing all data from tApp
- Test case:
clearAll
Expected: All students, tasks and groups cleared from the application.
- Test case:
Help Window
- Opening the help window through command line
- Test case:
help
Expected: The help window pop up is displayed.
- Test case:
- Opening the help window through mouse input
- Test case: click on the help tab Expected: The help window pop up is displayed.
- Copying the User Guide url
- Test case: click on the “COPY URL” button in the help page Expected: The url for the User Guide is copied.
Saving data
-
Dealing with missing data files
- Test case: delete the
tApp.jsonfile from thedatafolder. Then, execute thetApp.jarfile. Expected: tApp application opens with the sample data provided in SampleDataUtil.java.
- Test case: delete the
-
Dealing with corrupted data files
-
Test case: delete the
taskssection of thetApp.jsonfile. Then, execute thetApp.jarfile. Expected: tApp application opens with no data. -
Test case: edit the
tApp.jsonfile so that some properties are invalid (e.g. Changing theisCompleteproperty of aTaskto contain a String instead of a boolean). Expected: tApp application opens with no data.
-
Effort
Our team has put in a significant amount of effort into making our application cater to the needs of CS2103/T Teaching Assistants. While AB3 had only dealt with the Person entity type, tApp stores data of 3 different entity types, Task, Student and Group.
Implementing this required a deep understanding of how AB3 was structured and implemented, in order to expand on its functionality.
Moreover, classes such as Student and Group interact in order to provide more utility to the user, adding another layer of difficulty to the implementation.
In addition, our group has added many commands in addition to the ones implemented by AB3. While AB3 had a total of 8 available commands, tApp has a total of 27 in order to accommodate for all the different entity types and features.
This required significant time and effort, as well as a good understanding of the Logic component of AB3. We also made significant changes to the UI, making it more appropriate
for this app, such as the introduction of the different colours for the different tags.