Developer Guide
Table of Contents
- Table of Contents
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
Acknowledgements
- We utilise an open-source CSV (comma-separated values) parser library called Opencsv to help aid the implementation of our import-csv command. Click here to find out more about Opencsv.
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
Fig. 1 - Overall 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 delete 1
.
Fig. 2 - Architecture interactions
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.
Fig. 3 - Interacting through the API interfaces
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
Fig. 4 - Structure of the UI Component
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
. - keeps a reference to the
InputHistory
component, because theCommandBox
relies on it to obtain previously entered commands by the user
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
Fig. 5 - Structure of the Logic Component
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses theTailorParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResult
object which is returned fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
Fig. 6 - Interactions of a delete command inside the Logic Component
DeleteCommandParser
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:
Fig. 7 - Classes in Logic that are involved in parsing
How the parsing works:
- When called upon to parse a user command, the
TailorParser
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 theTailorParser
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. - The following Figure 8 depicts parsing in action:
Fig. 8 - Parsing of commands that take in arguments
Model component
API : Model.java
Fig. 9 - Structure of the Model Component
The Model
component,
- stores the content data i.e., all
Person
,Task
andModule
objects (which are contained in aUniquePersonList
,PriorityTaskList
andUniqueModuleList
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 the task list data i.e., all
Task
objects (which are contained in aPriorityTaskList
object). - stores the module list data and its default group mappings (in a
UniqueModuleList
object) - stores a
VersionedContents
object that stores the previous states of content data (to supportundo
/redo
) - 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)
VersionedContents
stores versions of the Content
object, which in turn stores a ContactList
, PriorityTaskList
and UniqueModuleList
object. The class diagram for VersionedContents can be found below.
Fig. 10 - Structure of VersionedContents
Tag
list in the ContactList
, which Person
references. This allows ContactList
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects. This diagram is also truncated slightly as it does not show the Task classes.Fig. 11 - A better Model class diagram
Storage component
API : Storage.java
Fig. 12 - Structure of the Storage component
The Storage
component,
- can save contact list data, task list data and user preference data in json format, and read them back into corresponding objects.
- inherits from
ContactListStorage
,TaskListStorage
,UserPrefStorage
andModuleListStorage
, which means it can be treated as either 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.
Some examples include:
Class Name | What it is used for |
---|---|
CsvUtil | Checking and parsing CSV files for the import-csv command |
MailUtil | Launching the system default mail application and checking the input arguments |
Implementation
This section describes some noteworthy details on how certain features are implemented.
Task Manager feature
Implementation
This Task Manager feature is implemented similarly to how commands interact with the XYZManagers and the contact list, as seen in the architecture section. Below shows the important classes that were created:
Logic | Model | Storage | UI |
---|---|---|---|
NewTaskCommand | DuplicateTaskException | TaskListStorage | TaskCard |
NewTaskCommandParser | TaskNotFoundException | JsonTaskListStorage | TaskListPanel |
RemoveTaskCommand | Description | JsonSerializableTaskList | |
RemoveTaskCommandParser | Deadline | JsonAdaptedTask | |
Task | |||
ReadOnlyTaskList | |||
PriorityTaskList |
Most of these classes were linked to the respective XYZManager components. For example, LogicManager now tries to save to the storage’s contact list and task lists:
storage.saveContactList(model.getContactList());
storage.saveTaskList(model.getTaskList());
Users also now have 2 additional commands to add new tasks and delete existing tasks, and the following sequence diagram shows how the new task command works in more detail:
Fig. 13 - Internal workings of a new task command
The current Task List uses a manually implemented priority system internally to sort/rank the tasks.
- The tasks are prioritised according to the closeness to the deadline. Ie, a Task with a deadline of 1 March will be in front of another Task with deadline of 1 December of the same year.
- The tasks are compared to each other using the
compareTo
method from theComparable
java interface
Design Considerations
Aspect: Extensibility
- Extensibility was heavily considered when implementing this feature. For Instance,
- A ReadOnlyTaskList was done instead of just a single TaskList class, to allow for multiple versions of a Task List being used if desired. Ie perhaps a Task List that is sorted according to a new “Emergency” level instead of just date-time.
- Deadline and Description classes were used instead of just a String and a LocalDateTime field to make the codebase more consistent with one another as seen from Person and its corresponding fields. This also would then allow a consolidated parsing and checking via the utilities.
Aspect: Conformity
- To allow the entire application to look like it has been coded by one person, the implementation of this task manager
feature was implemented in a similar way as to how AddressBook/ContactList is implemented, along with its interactions
with the XYZManagers.
- An example would be to include a new
TaskListStorage
Interface for theStorage
Interface to extend from. This hence provides the methods and an interface/facade for other parts of the code to perform task list operations on. - Another example would be how the Description and Deadlines for a
Task
are represented as individual classes instead of a String and a non-wrapped LocalDateTime, respectively. This is similar to howPerson
wraps the individual student attributes like Name and Email. This also allows the Description and Deadline objects to be created separately and allow for finer control over the codebase.
- An example would be to include a new
Undo/redo feature
Implementation
The undo/redo mechanism is facilitated by VersionedContents
. It extends Content
with an undo/redo history, stored internally as an contentStateList
and currentStatePointer
. Additionally, it implements the following operations:
-
VersionedContents#commitContent()
— Saves the current content state in its history. -
VersionedContents#undoContents()
— Restores the previous content state from its history. -
VersionedContents#redoContents()
— Restores a previously undone content state from its history.
These operations are exposed in the Model
interface as Model#commitContent()
, Model#undoContents()
and Model#redoContents()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedContents
will be initialized with the initial content state, and the currentStatePointer
pointing to that single content state.
Fig. 14 - Undo/Redo State 0
Step 2. The user executes delete 5
command to delete the 5th student in the contact list. The delete
command calls Model#commitContent()
, causing the modified state of the content after the delete 5
command executes to be saved in the contentStateList
, and the currentStatePointer
is shifted to the newly inserted content state.
Fig. 15 - Undo/Redo State 1
Step 3. The user executes add n/David …
to add a new student. The add
command also calls Model#commitContent()
, causing another modified content state to be saved into the contentStateList
.
Fig. 16 - Undo/Redo State 2
Model#commitContent()
, so the content state will not be saved into the contentStateList
.
Step 4. The user now decides that adding the student was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undoContents()
, which will shift the currentStatePointer
once to the left, pointing it to the previous content state, and restores the content to that state.
Fig. 17 - Undo/Redo State 3
currentStatePointer
is at index 0, pointing to the initial content state, then there are no previous content states to restore. The undo
command uses Model#canUndoContent()
to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
The following sequence diagram shows how the undo operation works:
Fig. 18 - Undo Sequence Diagram
UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The redo
command does the opposite — it calls Model#redoContents()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the content to that state.
currentStatePointer
is at index
contentStateList.size() - 1
, pointing to the latest contact list state, then there are no undone content states to
restore. The redo
command uses Model#canRedoContent()
to check if this is the case. If so, it will return an error
to the user rather than attempting to perform the redo.
Step 5. The user then decides to execute the command list
. Commands that do not modify the content, such as list
, will usually not call Model#commitContent()
, Model#undoContents()
or Model#redoContents()
. Thus, the contentStateList
remains unchanged.
Fig. 19- Undo/Redo State 4
Step 6. The user executes clear
, which calls Model#commitContent()
. Since the currentStatePointer
is not pointing at the end of the contentStateList
, all content states after the currentStatePointer
will be purged. Reason: It no longer makes sense to redo the add n/David …
command. This is the behavior that most modern desktop applications follow.
Fig. 20 - Undo/Redo State 5
The following activity diagram summarizes what happens when a user executes a new command:
Fig. 21 - Summary of an execution of a new command
Design considerations:
Aspect: How undo & redo executes:
-
Alternative 1 (current choice): Saves the entire content.
- Pros: Easy to implement.
- Cons: May have performance issues in terms of memory usage.
-
Alternative 2: Individual command knows how to undo/redo by
itself.
- Pros: Will use less memory (e.g. for
delete
, just save the student being deleted). - Cons: We must ensure that the implementation of each individual command are correct.
- Pros: Will use less memory (e.g. for
We decided to go with alternative 1 as the memory usage expected of TAilor is not high, since users are not expected to enter many content committing comments. The expected memory usage is not high as well, as the PersonList, TaskList and ModuleList are generally not space intensive.
Another drawback for alternative 2 was undoing a command by doing its reverse implementation might not return it to the
same state. For example, after delete 1
, we might save the student just deleted, and set add "student"
as the undo
functionality. However, if we do add "student"
, the student will be added to the end of the list, which does not exactly
undo
the effect of the original delete 1
.
Import CSV feature
Implementation
The following classes were created in the process of implementing the import-csv
command :
Logic | Commons |
---|---|
ImportCsvCommand | CsvUtil |
ImportCsvCommandParser |
The external library used for reading CSV files is OpenCSV. OpenCSV supports a host of functions that allow one to
manipulate and work with CSV files. The command utilizes the CSVReader
from the library to read the files.
One important assumption made while implementing the import-csv
command is that the files are expected to conform to
the format defined by LumiNUS (the learning management system used by NUS). This however, can be modified and extended
to cater to other systems as well.
ImportCsvCommand takes in the path argument for the CSV file, which is parsed to retrieve the contents and load them into TAilor’s database. Exception handling has been done alongside checks (file not found, io, csvvalidation etc)
Design Considerations
Aspect: Motivation
CSV files are by far one of the most commonly used formats for organizing large
amounts of data in an efficient manner. Since they are plain text files, they are
easier to transfer onto a spreadsheet or another storage database regardless of
the software being used. Since LumiNUS provides a way to import student data from CSV files,
the user would not have to go through the repeated, error-prone process of
manually adding each student’s data to the database. import-csv
automates this process and provides
a one-command solution to this problem.
Aspect: Defensive Coding
- The import-csv command has been created in a manner that checks for most possible places where the user could go wrong and provides guidance to correct them through the error messages and the user guide section.
- This command is designed to be very easy to use for the current target users, which are TAs teaching a NUS module
which implies that they would have manager access on LumiNUS.
- The student database exported from LumiNUS conforms exactly to our csv file requirements and hence, any beginner user would be able to successfully use this command as long as they follow the directions provided in the user guide.
Aspect: Usability and Improved User Experience
- One great feature that the import-csv focuses on is that it adds student contacts from the csv file additively to
the student list. Essentially, if some student details already exist in the roster then importing a csv file would not
replace the previous students’ data but instead extend the list.
- This is extremely useful for TAs who are teaching more than one module and would get different excel files from LumiNUS. To prevent increasing administrative requirements on user’s end, we will not need them to merge the files on their end, instead they can convert their excel sheets to csv and simply import one after the other.
- As such if the user prefers updating their csv locally and importing again then the command handles that situation too by ignoring duplicate students and simply importing the new updates.
Mailing feature
Implementation
This Mailing feature enables the user to initiate the system default mail application (if present). In order to achieve this, Java AWT (Abstract Window Toolkit) API is used. Below shows the important classes that were created:
Logic | Util |
---|---|
MailIndexCommand | MailUtil |
MailIndexCommandParser | |
MailXCommand | |
MailXCommandParser | |
MailAllCommand |
MailUtil class contains the interaction of TAilor with the desktop mail application. All the commands
call a launchMail
method in this class to accomplish their respective functionalities.
mail-index
command allows the user to email a specific student in the contact list based on their index, as displayed
in the application. mail-x
command enables the user to add multiple prefix-based arguments, using which multiple
students can be mailed in one go. The arguments act as the criteria based on which students are
considered to be a part of the mail group. The mail collation happens based on a descriptor class that takes care of
processing the individual arguments. mail-all
command is the solution if the user wants to email everyone
in the contact list without any filters. This command allows the user to perform bulk emails.
The following is the class diagram for the MailIndexCommand
class :
Fig. 22 - Summary of an execution of a new command
The following sequence diagram shows how the mail-x
operation works:
Fig. 23 - Summary of an execution of a new command
The following sequence diagram shows how the mail-all
operation works:
Fig. 24 - Execution of a `mail-all` command
Design Considerations
Aspect: Motivation
This feature forms an integral part of automating communication for the user with the contacts present in the contact list. Mail commands allow the user to conveniently mail one or more students from the contact list. The main functionality of all the mail commands is that they would input the receiver’s address for the user in the system default mail application, from where the user can continue on completing the mail on the external application.
Aspect: Compatibility
Mailing feature works across all the popular operating systems. It is able to operate with all mailto compatible mail applications as long as the default launching application has been set for the system.
Aspect: Extensibility
New capabilities for the mailing commands like cc, bcc and subject can be as the arguments without major changes in the underlying architecture of the product.
Aspect: Modularity
Mailing feature comprises well-defined, independent components which leads to better maintainability. All the components
were implemented and tested in isolation before being integrated with the product. An example of this is the MailUtil
class, which allows for testing compatibility of the system before integrating with the product to process commands.
Setting a Default Group for a particular Mod
Implementation
The following classes were created/edited in the process of implementing the set-default-group
command:
Logic | Model | Storage |
---|---|---|
SetDefaultCommand | DuplicateModuleException | ModuleListStorage |
SetDefaultCommandParser | ModuleNotFoundException | JsonModuleListStorage |
ModuleList | JsonSerializableModuleList | |
UniqueModuleList | JsonAdaptedModule |
The core idea behind this implementation is that there exists an empty UniqueModuleList
which is a list of Mod
.
Every Mod object has a defaultGroup
attribute that initially is unassigned. When a user enters the command set-default-group m/MOD g/GROUP
, the code:
- Uses
Model#doesModExistInList
to check if theMod
exists inUniqueModuleList
. - If it exists, get the previous default group using
Model#retrievePrevDefault
and update it. - Else add the
Mod
to theUniqueModuleList
with the given defaultGROUP
using theModel#setDefaultGroup
command.
Now when a user adds a new student using the add
command:
- If the group argument has been passed, the code is run normally
- If the group argument has not been passed, the code retrieves the default group from the
UniqueModuleList
and throws an error if the given mod has no default group set.
Similar to the TaskList implementation most of these classes are linked to the respective XYZManager components. For example, LogicManager now tries to save to the storage’s moduleList as well:
storage.saveModuleList(model.getModuleList());
The sequence diagram for the command set-default-group m/CS2103T g/W12-1
follows the parsing as mentioned in Fig 8.0
above and the specific functioning of the command can be found in the sequence diagram below:
Fig. 25 - Execution of a `set-default-group` command
Design Considerations
Aspect: Motivation
With this feature we aim to help facilitate a better user experience and follow through on TAilor’s primary objective of making administrative tasks less tedious and rudimentary. By setting a default group, the use need not worry about repeatedly entering the same group value for several students over an extended period of time.
Aspect: Conformity
-
This feature merges with the functionality of the Add and Edit Commands seamlessly. If the default value has been set, then the group argument is essentially optional for the users and TAilor will update the student’s data to include the default group value. If a group argument is provided, however, then TAilor prioritises the field provided by the user over the previously set default group value.
-
The implementation of the UniqueModuleList is extremely similar to how the ContactList and TaskList is implemented, with the interactions with the XYZManagers the same.
- An example would be to include a new
ModuleListStorage
Interface for theStorage
Interface to extend from. This hence provides the methods and an interface/facade for other parts of the code to perform module list operations on.
- An example would be to include a new
Refill previously typed command feature
Implementation
This feature is facilitated by InputHistoryManager
. It implements InputHistory
, and stores the previously entered
user commands internally as a previousInputs
and indexPointer
. InputHistoryManager
also implements:
-
InputHistoryManager#storeInput(input)
— Stores the entered input in theInputHistoryManager
. -
InputHistoryManager#getPreviousUserInput()
— Returns the previously entered input. -
InputHistoryManager#getNextUserInput()
— Returns the next entered input.
Given below is an example usage scenario and how the mechanism behaves at each step.
Step 1. The user launches the application for the first time. The InputHistory
will be initialized with an empty
previousInputs
, and the indexPointer
pointing to 0
. The CommandBox
is empty upon initialization as well.
Fig. 26 - Previous input state 0
Step 2. The user enters the command delete 1
. The CommandBox
will call storeInput("delete 1")
on InputHistory
.
The indexPointer
will increment by 1, pointing to 1
. The CommandBox
clears itself upon entering the command.
Fig. 27 - Previous input state 1
Step 3. The user enters the command delet 1
. The CommandBox
will call storeInput("delet 1")
. The indexPointer
will increment by 1, pointing to 2
. However, as the input command is invalid, the CommandBox
does not clear itself
upon entering the command.
Fig. 28 - Previous input state 2
Step 4. When the user presses the ↑ button, the CommandBox
will call getPreviousUserInput()
, which decrements
the pointer by 1, pointing it to "delet 1"
. The text in CommandBox
will still remain as “delet 1”.
Fig. 29 - Previous input state 3
indexPointer
is at index 0, where
previousInputs
is empty, then there are no previous inputs to refill. The CommandBox
will call
InputHistoryManager#canGetPrevInput()
to check if theres any previous inputs. If not, the CommandBox
will simply not
be updated.
The following sequence diagram demonstrates how the refill previous input works
Fig. 30 - Previous input Sequence Diagram
Step 5. When the user presses the ↑ button, the CommandBox
will call getPreviousUserInput()
, which decrements
the pointer by 1, pointing it to "delete 1"
. The text in CommandBox
will change to “delete 1”.
Fig. 31 - Previous input state 4
Step 6. When the user presses the ↓ button, the CommandBox
will call getNextUserInput()
, which increments the
pointer by 1, pointing it to “delete 1”. The text in the CommandBox
will update to “delete 1”.
Fig. 32 - Previous input state 3
indexPointer
is at index
previousInputs.size() - 1
, then there are no previous inputs to restore. The CommandBox
will call
InputHistoryManager#canGetNextInput()
to check if there’s any next inputs. If not, the CommandBox
will simply not
be updated.
Finally, the user decides to enter a new command, undo
. The CommandBox
will call storeInput("undo")
. The
indexPointer
will update to point to 3
. The CommandBox
clears itself upon entering the command.
Fig. 33 - Previous input state 5
Design Considerations
Aspect: Motivation
As quick typers, it is inevitable for us to make typos once in a while. In those cases, it is very convenient if we
could quickly refill the CommandBox
with the mistyped input, and correct the mistake there. This features serves to
meet that need.
Aspect: Coupling
To reduce the coupling introduced by this feature as much as possible, the InputHistoryManager
object only has an
association with the CommandBox
UI part. As TAilor is designed only with 1 point of input, the InputHistoryManager
only needs to be associated with the CommandBox
.
Aspect: Extendability
If the application is expanded to include multiple points of input, each input box can be associated with their own instance
of InputHistoryManager
, which can allow each of them to store their own input histories.
Getting help
Implementation
The following classes were created/modified in the process of implementing help
command :
Logic |
---|
HelpCommand |
HelpCommandParser |
The main idea behind this extension is that the user may request for help on how to use a particular command, what are the arguments that are accepted by that command, and what is the expected syntax.
There are two main ways in which this command can be used :
-
help
will open a modal with a link to the user guide of the product. -
help COMMAND_WORD
will output the usage instructions of theCOMMAND_WORD
and a short description as to what it does.
Essentially COMMAND_WORD
is an optional argument to the help
command which gets parsed using the HelpCommandParser
.
The following is the sequence diagram of help
command’s execution :
Fig. 34 - Help command execution
Design Considerations
Aspect: Motivation
This feature allows the user to access the user guide and check the usage of specific commands. The aim of this
feature is to provide user the convenience to access the usage instructions of a particular command without
referring to the user guide everytime. It forms an extension over the original help
command.
This feature was inspired from the --help
flag that is present in most modern day CLI tools.
Aspect: Maintainability
help
command’s extension was done in a manner that any new command can be easily incorporated into the
functionality without too many changes. In this way, it is highly maintainable.
Aspect: Robustness
help
command is able to tolerate unpredictable or invalid input. Appropriate exception handling has been done to
ensure that it does not process erroneous input.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- is a teaching assistant from the School of Computing
- has a need to manage a significant number of students/contacts
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: The app will help to facilitate a Teaching Assistant’s journey for multiple modules, particularly with some tedious administrative tasks.
User stories
Priorities: High (must have), Medium (nice to have), Low (unlikely to have)
Priority | User | Function | Benefit |
---|---|---|---|
priority.High | As a Teaching Assistant, | I am able to see my students’ contact details | so that I can more easily communicate messages to them |
priority.High | As a Teaching Assistant, | I can send bulk emails to students to remind them of the deadlines or to make general PSAs | so that I don’t miss on passing them crucial information |
priority.High | As a Teaching Assistant, | I can know the number of students in each of my tutorial classes and their names | This helps me keep track of attendance for each session |
priority.High | As a Teaching Assistant, | I can “tag” students with various tags | so that I can keep track of who to follow up on, who to check up on more often etc |
priority.High | As a Teaching Assistant | I can manually add new students into my contact list | so I have alternate methods to add students other than to rely on exporting from a file |
priority.High | As a Teaching Assistant | I can edit my students’ contact details manually | so that if they have any changes to their details, I can keep track of it and still be able to contact them |
priority.High | As a Teaching Assistant | I can delete students from my contact list | so I can make changes to my student list |
priority.High | As a new Teaching Assistant using this app | I am able to get help on how to use the app | so I can learn how to use this program |
priority.High | As a Teaching Assistant who makes typos often | I am able to go back to the mistyped command | so I can quickly correct spelling errors made |
priority.Medium | As a Teaching Assistant, | I can see the upcoming deadlines | so I prepare for it or remind students about it |
priority.Medium | As a Teaching Assistant, | I can keep track of how my students have been performing | so that I can better help the students who need more help |
priority.Medium | As a Teaching Assistant | I can see all the groups that I need to mark/supervise | so that I can track all my students and groups |
priority.Medium | As a Teaching Assistant, | I can manage consultations with my students with the calender system | so that I can more easily cross-reference my availability with my students |
priority.Medium | As a Teaching Assistant | I can know which student’s performance requires review and attention per assignment | so that I can reach out and offer help possibly in the form of a consultation. |
priority.Medium | As a Teaching Assistant | I can group students under different tutorial classes | so I can personalize messages to individual classes |
priority.Medium | As a Teaching Assistant, | I can receive anonymous feedback from my students | so that I can help my students in a more effective way. |
priority.Medium | As a Teaching Assistant | I can automatically remind students about deadlines and examinations | so that my students will be reminded about the upcoming deadlines easily |
priority.Low | As a Teaching Assistant, | I can export the necessary numbers about all students in my class from assignment marks to attendance to a CSV file | so that I can perform a better analysis of the semester on whole |
priority.Low | As a Teaching Assistant, | I can track student’s assignment progress | so that I know which student to focus on and give reminders to |
priority.Low | As a Teaching Assistant who uses different devices | I can sync my data over different devices | so I can use the app over diff devices |
priority.Low | As a first time user | I can see sample data | so I can see how the app can be used |
priority.Low | As a Teaching Assistant for a new class | I can share an introduction document with my students | so that they can get to know each other a little bit more before the first session |
priority.Low | As a Tech-Savvy Teaching Assistant who uses Telegram | I can create a telegram group and invite all students to it | so I can communicate to my students using telegram |
priority.Low | As a Tech-Savvy Teaching Assistant who uses Discord | I can create a discord channel and invite all my students to it | so I can communicate to my students using discord |
priority.Low | As a Teaching Assistant using Coursemology | I can receive notifications from Coursemology on the application | so I can quickly respond to my student’s questions and submissions on Coursemology |
priority.Low | As a Teaching Assistant who is involved in grading | I can automatically distribute grades to students easily | so my students will not have to manually wait or check for the grades to be released |
priority.Low | As a Teaching Assistant who takes makeup tutorials | I can add students temporarily to a class | so that I can have the students in my mailing list temporarily |
priority.Low | As a Teaching Assistant during unprecedented times | I can instantly create Zoom meetings using the Zoom SDK | so that I can automate my workflow for sending meeting invitations to the group |
priority.Low | As a Teaching Assistant | I can tag students for plagarism | so I can automatically inform my professors about plagiarism cases |
priority.Low | As a Teaching Assistant who is involved in grading | I can see a graph of trends about my students’ performance individually | so I can track the progress and improvement of my students |
priority.Low | As a Teaching Assistant | I can create aliases for websites that are commonly used by students | so that my students and I can access commonly visited websites easily |
priority.Low | As a Teaching Assistant teaching multiple modules | I am able to separate the management of the modules | so that I can be more organised in my work and teaching |
Use cases
(For all use cases below, the System is TAilor
and the Actor is the user
, unless specified otherwise)
Use case 1 (UC1): Importing an existing database
MSS
- User requests to import an existing file
- TAilor requests for the file location
- User specifies the file location
-
TAilor uploads the file
Use case ends.
Extensions:
-
4a. User requests to add more students manually (UC2)
User case ends
Use case 2 (UC2): Manually adding students
MSS
- User uses the ‘add’ command
-
TAilor updates the database with student details
Use case ends.
Extensions:
- 1a. User adds permanent student to the class group
- 1a1. User uses the permanent tag with student details
-
1a2. TAilor adds the student contact details to the respective group’s database
Use case ends.
- 1b. User adds temporary student to the class group
- 1b1. User uses the temporary tag with student details
- 1b2. TAilor asks for validity of temporary tag
- 1b3. User enters the lifespan of the entry
-
1b4. TAilor adds the student contact details to the respective group’s database
Use case ends.
Use case 3 (UC3): Finding a student
MSS
- User requests to find student through particular keywords
-
TAilor returns contact details of matching student
Use case ends.
Extensions:
- 2a. TAilor doesn’t find any matches
-
2a1. TAilor displays an empty list
User case ends
-
- 2b. TAilor finds more than one matching student
- 2b1. TAilor returns list of matching students
-
2b2. User enters index to select desired student
User 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 be able to hold up to 100 tasks 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.
- The code should be open source.
- Should not require internet connection.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Private contact detail: A contact detail that is not meant to be shared with others
- Tutor: A tutor is a teaching assistant for a particular module in NUS.
- Module: The subject being taught by the tutor.
- Group: A group of students belonging to a particular module managed under a tutor.
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 OR:
- Open the terminal on your PC and move to the directory where
TAilor.jar
is contained in. Then, runjava -jar TAilor.jar
the application. We recommend macOS users to use this method of starting the application to avoid errors.
- Expected: Shows the GUI with a set of sample contacts/students and tasks. The window size may not be optimum.
- Download the jar file and copy into an empty folder
-
Closing the application
-
Type in
exit
in the input/command box -
Press the close button for the application at the top right corner of the window.
-
-
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.
-
Adding a student
-
Adding a student using the
add
command.- Preqrequisites: User needs to have the details of the following attributes of a student:
- Name (e.g. Alex)
- Student Number (e.g. A1234567B)
- Email (e.g. alex@example.com)
- Module (e.g. CS2030S)
- Group (e.g. 10G)
-
Test case:
add n/Alex a/A0001112B e/alex@example.com m/CS2030S g/10G
when there are already 2 students in the list
Expected: A new student with nameAlex
, student numberA1234567B
, emailalex@example.com
, moduleCS2030S
and group10G
is added to the student list. The index number assigned toAlex
will be 3, the last pre-existing student + 1.
Details of the added student will be shown in the feedback box. -
Test case:
add n/Bob a/A0001112B e/bob@example.com m/CS2030S g/10G
when there are already 3 students in the list, including Alex above.
Expected: No new student will be added, as the provided student number already belongs to someone in the list (Alex, from the above test case). Error details are shown in the feedback box. -
Test case:
add n/Alexis a/A0001113B e/alex@example.com m/CS2030S g/10G
when there are already 3 students in the list, including Alex above.
Expected: No new student will be added, as the provided email address already belongs to someone in the list (Alex, from the above test case). Error details are shown in the feedback box. -
Test case:
add a/A0001114B e/charles@example.com m/CS2030S g/10G
without conflicting student number and emails present in the list.
Expected: No new student will be added, as there is no name provided. Error details are shown in the feedback box. -
Test case:
add n/Dickson e/dson@example.com m/CS2030S g/10G
without conflicting student number and emails present in the list.
Expected: No new student will be added, as there is no student number provided. Error details are shown in the feedback box. -
Test case:
add n/Eliza a/A0001115B m/CS2030S g/10G
without conflicting student number and emails present in the list.
Expected: No new student will be added, as there is no email address provided. Error details are shown in the feedback box. -
Test case:
add n/Felicia a/A0001116B e/felicia@example.com g/10G
without conflicting student number and emails present in the list.
Expected: No new student will be added, as there is no module provided. Error details are shown in the feedback box. -
Test case:
add n/George a/A0001117B e/george@example.com m/CS2030S
when there is no default group set for the moduleCS2030S
, and without any conflicting student number and emails present in the list.
Expected: No new student will be added, as there is no group provided. Error details are shown in the feedback box. - Test case:
add n/Hector a/A0001118B e/hectorzz@example.com m/CS2030S
when there is a default group set for the moduleCS2030S
, for exampleGroup1
. Also, there are no conflicting student number and emails present in the list, that currently contains 3 people.
Expected: A new student with nameHector
, student numberA0001118B
, emailhectorzz@example.com
, moduleCS2030S
and groupGroup1
is added to the student list. The index number assigned toHector
will be 4, the last pre-existing student + 1.
Details of the added student will be shown in the feedback box.
- Preqrequisites: User needs to have the details of the following attributes of a student:
-
Adding multiple students using the
import-csv
command-
Prerequisites: There needs to exist a csv file at the given path and start with an empty contactlist.
-
Test case:
import-csv src/test/data/ImportCsvTest/sample-tutorial-data.csv
where there is no other student data. Expected: New students are added with the details matching in the sample-tutorial-data.csv. -
Test case:
import-csv ./second-sample-tutorial-data.csv
where there is a csv file in your current directory. Expected: New students are added with the details matching in the second-sample-tutorial-data.csv. Students with existing names/matric numbers are skipped.
-
Editing a student
-
Editing an existing student in the student list.
-
Prerequisites: List all students using the
list
command. Multiple students in the list. -
Test case:
edit 1 n/Bob
when the first student in the list has a name ofAlex
.
Expected: The name of the first student is edited, fromAlex
toBob
. Details of the edit are shown in the feedback message. -
Test case:
edit 0 n/Bob
Expected: No student is edited. Error details shown in the status message. -
Other incorrect delete commands to try:
edit
,edit x
,...
(where x is larger than the list size)
Expected: Similar to previous. -
Test case:
edit 1
with at least 1 student in the list.
Expected: Similar to previous, as there are no arguments specified to be edited
-
Deleting a student
-
Deleting a student while all students are being shown.
-
Prerequisites: List all students using the
list
command. Multiple students in the list. -
Test case:
delete 1
Expected: First student is deleted from the list. Details of the deleted student shown in the feedback message. -
Test case:
delete 0
Expected: No student is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
-
Deleting a student while only some students are shown.
-
Prerequisites: Find some students using the
find
command. Multiple students in the list, depending on the result of thefind
command. -
Test case:
delete 1
Expected: First student is deleted from the list. Details of the deleted student shown in the feedback message. Performing alist
command will also show that the deleted student is no longer in the list. -
Test case:
delete 0
,delete
,delete x
,...
Expected: Similar to the erroneous test cases from the list command above.
-
Mailing student(s)
-
Mailing an individual student from the contact list
-
Prerequisites: Multiple students in the contact list.
-
Test case:
mail-index 1
Expected: System default mail application opens up with the receiver’s field filled with the email address of the student at the specified index ie 1. -
Test case:
mail-index 2
Expected: System default mail application opens up with the receiver’s field filled with the email address of the student at the specified index ie 2.
-
- Mailing all the students in a particular module
-
Prerequisites: Multiple students in the contact list belonging to the module CS2103 (example scenario).
-
Test case:
mail-x m/CS2103
Expected: System default mail application opens up with the receiver’s field filled with the email addresses of all the students belonging to CS2103 module in the contact list.
-
-
Mailing everyone in the contact list
-
Prerequisites: Multiple students in the contact list.
-
Test case:
mail-all
Expected: System default mail application opens up with the receiver’s field filled all the email addresses of students in the entire contact list.
-
Creating a Task
-
Creating a new task to keep track of.
-
Prerequisites: Brief description and deadline of the task should be known.
-
Test case:
newtask Do Homework by/2022-01-03T16:30
when there are already 2 tasks in the task list.
Expected: A new task with descriptionDo Homework
and deadline of 3 January 2022, 4:30pm will be added to the task list. The index number assigned to this task will be 3, the last pre-existing task + 1.
Details of the added task will be shown in the feedback box. -
Test case:
newtask Mark Tutorial
Expected: No task is added as no deadline is provided. Error details shown in the status message. -
Test case:
newtask by/2022-02-04T17:29
Expected: No task is added as no description is provided. Error details shown in the status message. -
Test case:
newtask Mark Lab 1 by/2022-02-04 17:29
Expected: No task is added as the provided date format is incorrect. Error details shown in the status message. -
Test case:
newtask Mark Lab 1 by/2022-02-29T17:29
Expected: No task is added as 2022 is not a leap year, and has no Feb 29. Error details shown in the status message.
-
Deleting a Task
-
Deleting a task from the task list.
-
Prerequisites: Multiple tasks in the task list.
-
Test case:
del-task 1
Expected: First task is deleted from the list. Details of the deleted task shown in the feedback message. -
Test case:
del-task 0
Expected: No task is deleted. Error details shown in the status message. -
Other incorrect delete task commands to try:
del-task
,del-task x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Undoing/Redoing commands
-
Undoing a command
-
Prerequisites: There must be an undo-able command executed beforehand in the same usage session.
-
Test case:
undo
and the previous command added a new student (add
command)
Expected: The add command is undone, and the new student no longer appears in the student list. Feedback is shown in the feedback box that the undo command has been done. -
Test case:
undo
and the only previous commands arelist
orfind
commands
Expected: No undo-able command is available. Nothing changes, and an error pops up indicating that there is nothing to undo. -
Test case:
undo
and there are no commands done yet since launching the application
Expected: Same as above.
-
-
Redoing a command
- Similar to the undo command, flipping
undo
intoredo
, before into after.
- Similar to the undo command, flipping
Getting help
-
Getting help through user guide
-
Prerequisites: None
-
Test case:
help
Expected : A popup opens with a link to the user guide of the application.
-
-
Getting help about a specific command
-
Prerequisites : None
-
Test case:
help add-task
Expected : The usage instructions of theadd-task
command are displayed.
-
Saving data
-
Dealing with missing/corrupted data files (contactlist.json, tasklist.json, modulelist.json)
- Missing/corrupted data can occur from some ways listed below: (non-exhaustive!)
- The .json files have been tampered with, intentionally or not.
- The .json files cannot be read by TAilor upon startup.
-
Currently, TAilor does not have any in-built back up system. As such, we recommend users to do manual back ups once in a while, to ensure that everything is saved at a restore point.
-
Additionally, if users decide to modify the .json files manually to add in new data, it is also recommended for them to make a backup copy of the data files before doing so.
- In the case of unfortunate events where the user did not make a back up and data is indeed lost, the user has no choice but to manually enter in the data again from scratch.
- Missing/corrupted data can occur from some ways listed below: (non-exhaustive!)
-
TAilor should save to the 3 data files automatically, upon the execution of most commands. As such, there is no need to perform a “save” command to ensure that the data files are updated.