Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Feature Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Command summary
- Appendix: Planned Enhancements
Acknowledgements
We would like to thank:
- CS2103T AY22/23 Semester 2 teaching team for imparting valuable knowledge, skills and guidance
-
SE-edu AddressBook 3 which
QuickContactsis built on - Open-source libraries used in
QuickContacts: - Colors from Ayu
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

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.
Interaction between architecture components
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

Each of the four main components (also shown in the diagram above),
- 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 parts e.g.CommandBox, ResultDisplay, PersonListPanel, MeetingListPanel, 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
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. - depends on some classes in the
Modelcomponent, as it displaysPersonobject residing in theModel.
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 theQuickcContactsParserclass to parse the user command. - This results in a
Commandobject (more precisely, an object of one of its subclasses e.g.,AddCommand) which is executed by theLogicManager. - The command can communicate with the
Modelwhen it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResultobject which is returned back fromLogic.
The Sequence Diagram below illustrates the interactions within the Logic component for the execute("delete 1") API call.

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:

How the parsing works:
- When called upon to parse a user command, the
QuickContactsParserclass creates anXYZCommandParser(XYZis a placeholder for the specific command name e.g.,AddCommandParser) which uses the other classes shown above to parse the user command and create aXYZCommandobject (e.g.,AddCommand) which theQuickContactsParserreturns back as aCommandobject. - All
XYZCommandParserclasses (e.g.,AddCommandParser,DeleteCommandParser, …) 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
Personobjects (which are contained in aUniquePersonListobject) andMeetingobjects (which are contained in aUniqueMeetingListobject). - stores the currently ‘selected’
Personobjects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a
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 Person model,
- consists of individual classes
Name,Phone,Email,AddressandTagwhich are used to store the respective information of aPerson.

The Meeting model,
- consists of individual classes
Title,DateTime,Person,LocationandDescriptionwhich are used to store the respective information of aMeeting.
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
QuickBookStorageandUserPrefStorage, 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.quickcontacts.commons package.
Feature Implementation
Create, Edit and Delete Operations for Person and Meeting
This section describes some noteworthy details on how certain features related to Person and Meeting are
implemented. Person and Meeting have similar functionality and how they are implemented are similar. Without loss of
generality, the specifications below can be applied to both class of objects, unless specified otherwise.
In this section:
-
Objectis used to representPersonandMeeting - Correspondingly,
UniqueListis used to representUniquePersonListandUniqueMeetingList - Correspondingly,
AddXYZCommandis used to representAddCommandandAddMeetingCommand - Correspondingly,
EditXYZCommandis used to representEditCommandandEditMeetingCommand - Correspondingly,
DeleteXYZCommandis used to representDeleteCommandandDeleteMeetingCommand - Correspondingly,
AddParseris used to representAddCommandParserandAddMeetingCommandParser - Correspondingly,
EditParseris used to representEditCommandParserandEditMeetingParser - Correspondingly,
DeleteParseris used to representDeleteCommandParserandDeleteMeetingCommandParser
Depending on which object functionality you are exploring, simply substitute the general object (Object or
UniqueList) with the specific object.
We write in a general so that we cover breadth, and that we may adhere to DRY principle.
Adding
Description
The AddXYZCommand handles the addition of Object into QuickContacts. See the syntax for AddXYZCommand
here.
Implementation
When adding an Object the control flow is as follows:
- The user queries the
UIto add using theaddoraddmcommand. -
UIcalls theQuickContactsParserthroughLogicManagerto initiate anAddParserobject. -
QuickContactsParserthen passes the arguments to theAddParserobject. -
AddParserinitiates anAddXYZCommandobject. -
AddXYZCommandobject is passed all the way back toLogicManager. -
LogicManagercallsexecute()onAddXYZCommand. -
AddXYZCommandupdates the model and returns aCommandResulttoLogicManager. -
LogicManagerupdates theUniqueList.
Below is the Sequence Diagram as a concrete example for a Person:

Exceptions
The AddMeetingCommand throws a CommandException if the object’s names is found in the address book (i.e.
no person in the address book has a matching name). The name must match exactly (case-sensitive) or else the
CommandException will be thrown.
Editing
Description
The EditXYZCommand is responsible for handling the editing of an Object in QuickContacts. It allows users to modify the
details of a specific Object. See the syntax for EditXYZCommand here.
Implementation
When editing a meeting, the control flow is as follows:
- The user queries the UI to edit a
Objectusing theeditoreditmcommand. - The UI calls the
QuickContactsParserthroughLogicManagerto initiate anEditParserobject. -
QuickContactsParserthen passes the arguments to theEditParserobject. -
EditParserinitiates anEditXYZCommandobject. -
EditXYZCommandobject is passed all the way back toLogicManager. -
LogicManagercallsexecute()on theEditXYZCommand. -
EditXYZCommandupdates the model with the editedObjectdetails and returns aCommandResulttoLogicManager. -
LogicManagerupdates theUniqueListwith the new information by replacing the old with the new object.
Below is the Sequence Diagram as a concrete example for a Person:

Exceptions
EditMeetingCommand throws a CommandException if any one of the Person’s name is not found in QuickContacts. The
name must match exactly (case-sensitive).
Deleting
Description
The DeleteXYZCommand handles the deletion of an Object from QuickContacts. See the syntax for DeleteXYZCommand
here.
Implementation
When deleting an Object, the control flow is as follows:
- The user queries the UI to delete using the
deleteordelmcommand. - The UI calls the
QuickContactsParserthrough LogicManager to initiate aDeleteParserobject. -
QuickContactsParserthen passes the arguments to theDeleteParserobject. -
DeleteParserinitiates aDeleteXYZCommandobject. -
DeleteXYZCommandobject is passed all the way back toLogicManager. -
LogicManagercallsexecute()onDeleteXYZCommand. -
DeleteXYZCommandupdates the model and returns aCommandResulttoLogicManager. -
LogicManagerupdates theUniquePersonListby deleting thePersonfrom it.
Below is the Sequence Diagram:

Exceptions
The DeleteXYZCommand throws a CommandException if the specified index is not found in QuickContacts.
Finding Person
Description
The FindCommand finds persons in the address book. See the syntax for FindCommand here.
Implementation
When finding meetings, the control flow is as follows:
- The user queries the
UIto find using afindcommand. -
UIcalls theQuickContactsParserthroughLogicManagerto initiate aFindCommandParserobject. -
FindCommandParsertakes in a list of names and creates aFindCommandobject. -
FindCommandis executed, and aNameContainsKeywordsPredicateis passed to theupdateFilteredPersonListmethod in theModelcomponent. -
LogicManagercreates aNameContainsKeywordsPredicate, passing it to theupdateFilteredPersonList()method in theModelcomponent. -
UIdisplays the filtered meetings to the user.
Below is the Sequence Diagram:

Exceptions
The FindCommand throws a CommandException if no names are provided.
The names no need to match exactly (case-INsensitive) but the contacts are only filtered by one of the contact’s names,
as space is used as a delimiter.
Difference in Meetings
Implementation
For meetings, the usage and implementation is similar, but the FindMeetingCommand will search for matching names in the
meetings list similar to FindMeeting and returns meetings that satisfy the search criteria
(i.e. if the meeting has at least one contact that matches the input name).
However, findm can be used without arguments to list all meetings. Thus, unlike find, findm will not throw exceptions if not given
any arguments.
Exporting and importing of contacts
Description
Exporting generates a JSON for the contacts at the indices given.
For example, export p/1 p/2 generates a JSON for the first and second contacts.
Example JSON:
[ {
"name" : "Alice Pauline",
"phone" : "94351253",
"email" : "alice@example.com",
"address" : "123, Jurong West Ave 6, #08-111",
"tagged" : [ "friends" ]
}, {
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
"address" : "311, Clementi Ave 2, #02-25",
"tagged" : [ "owesMoney", "friends" ]
} ]
The JSON is generated using the Jackson library, through the use of the JsonUtil utility class. The JSON can be pasted in again proceeding the import command to import the information in the export command
Design Considerations
Alternative 1: Use some other format (eg. XML or YAML) for exporting
Could provide more readable and/or less text for copying.
Alternative 2 (current choice): Use existing JSON format
Benefit: can directly copy-paste to and from the data files that already exist in the system.
Implementation
Here we only describe the ExportCommand. Import is the same, besides step 5. where it instead calls add on the model to add the specified objects in JSON (similar to how storage loads the save file)
Control flow is as follows.
- The user queries the
UIto export using a export command. -
UIcalls theQuickContactsParserthroughLogicManagerto initiate a `ExportCommandParser` object. -
ExportCommandParsercreates a `ExportCommand` object. -
ExportCommandis returned toLogicManager. -
LogicManagerexecutes `ExportCommand`. -
ExportCommandqueriesModelManagerfor JSON string. -
ExportCommandreturns JSON string toLogicManagerandModelManager. -
UIoutputs the JSON string.
Below is the Sequence Diagram:

Difference in Meetings
Implementation
Meetings has additional functionality of returning meetings between two dates. This is implemented through the use of a
isBetween function implemented in the Meeting class. The program will first gather all the meetings in the
corresponding indexes provided, then search for meetings between the start and end dates. If either date is empty, then
only the other date is considered.
Exceptions
Using the exported JSON, one can then import it using import VALID_JSON.
Before importing, a check is done to make sure there are no duplicate values. This is done before the actual importing to ensure we do not have “half imports”.
Consider a situation where we have [Person2, Person3] in the system. If we
import [Person1, Person2, Person3, Person4] without considering duplicates first, Person1 will be imported
followed by the import of Person2 throwing a DuplicatePersonError, resulting in the command throwing a failure
message and Person4 not being imported but the system now has [Person1, Person2, Person3].
The JSON is parsed using the Jackson library. If the Jackson library is unable to parse the json, an error message
is thrown.
However, if the user wishes to “force import”, a f/ parameter is provided. This imports for each Person if the
Person does not already exist, and ignores those that do.
This allows the previous situation to complete with [Person1, Person2, Person3, Person4] in the system.
Autocompletion of Argument Prefixes
Autocompletion of command inputs is facilitated by the individual command parsers (XYZCommandParser) which are
implementing the Parser interface in the Logic component. Each XYZCommandParser implements how autocompletion
should work for that particular command by overriding Parser#getAutocompleteSuggestion. This action is triggered when
the user presses TAB when the command input starts with a valid command.
The CommandBox UI component is actively listening for TAB keystrokes by having a KeyPressedHandler which will
trigger XYZCommandParser#getAutocompleteSuggestion. A AutocompleteResult would then be returned to the CommandBox
which contains the Prefix to be appended to the current command input, or used to replace the last Prefix in the
current command input.
Design Considerations
Alternative 1: Autocomplete by appending the next relevant Prefix that is missing
- This will be easier to implement as all we need is to have a list of
Prefixthat is relevant for the command and cycle through and append those that are missing from the current command input. - Checking for missing
Prefixfrom the command input can be achieved with the help ofArgumentTokenizer. - Downside: some commands such as
editdoes not need all thePrefixas user might just want to modify two attributes. Simply cycling through and appending missingPrefixmight require users to backspace some unnecessaryPrefix.
Alternative 2 (current choice): Autocomplete by custom behaviour depending on the command
- This would require each
XYZCommandParserto implement their own behaviour on how autocompletion should behave for that particular command. - Benefit: There is more flexibility in customising how to best cater autocompletion for each individual command to better the user experience.
Traversal of Commands
Traversal of commands is facilitated by CommandHistory model in addition to KeyPressedHandler in the CommandBox UI component.
Internally, CommandHistory utilises LinkedList to store all the commands that have been executed by the user. Traversal of the list is facilitated by a static pointer.
CommandBox UI component is actively listening to the UP and DOWN keys which would be handled by the KeyPressedHandler, which is responsible for traversing the command history using CommandHistory.
The activity diagram below provides a visual representation of the flow of actions when the UP and DOWN keys are pressed.

DateTime parsing
Storing of dateTime (date and/or time) of Meeting is facilitated by DateTime.
The dateTime of a Meeting requires users to input a date, but leaves the time of the meeting to be optional. Internally, DateTime stores the date using LocalDate and the time using LocalTime. However, since the time is an optional field, the optionality of the time is implemented by wrapping LocalTime with the Java Optional class. This brings about various benefits and is further discussed below.
Moreover, DateTime allows for various formats of parsing in a dateTime value (22/02 3.30PM, 2202 1530, 22.02.2023 etc). This is facilitated by first having a list of formats for dates and times separately. Moreover, separators (., :, / etc) are maintained and inserted for each format dynamically. For example:
-
dd{SEP}MM{SEP}yyyyspecifies the format fordd/MM/yyyy,dd.MM.yyyyanddd-MM-yyyyfor separators/,.and-respectively.
This way, formats are easily extensible and maintainable. The parsing of dateTime inputs into LocalDate and LocalTime objects are facilitated by breaking up the input into 2 parts: date and time, before using LocalDate#parse and LocalTime#parse respectively.
Design Considerations
Aspect: How to encapsulate the time of a Meeting which is optional
-
Alternative 1: Have the time set to
nullif user does not provide the time.- This would risk
NullPointerExceptionbeing thrown if the time is not provided but there are attempts of accessing the time. - As a result of the point above, there will be many instances of null checks, which would contribute to unnecessary code verbosity.
- This would risk
-
Alternative 2: Make use of
LocalTime.MAXto represent that the time is not provided.- This alternative removes the risk of
NullPointerExceptionthat comes with Alternative 1. - However, there would still be many instances of checks whether the time equals to
LocalTime.MAX, which would contribute to unnecessary code verbosity.
- This alternative removes the risk of
-
Alternative 3 (current choice): Utilise Java
Optionalto wrap the time.- By doing so, there will not be any
NullPointerExceptionand enables us to make use of the provided methods (orElseetc.) that helps to carry out the logic based on the presence of the time.
- By doing so, there will not be any
Sort Meeting commands (only in meetings)
Sorting
Description
The SortMeetingCommand is a Java class that allows the user to sort meetings stored in a Model object based on a specified attribute, such as title, date and time, location, or description. The sorting is done by creating a Comparator for the specified attribute and passing it to the sortFilteredMeetingList method in the Model object. See the syntax here sort command.
Implementation
When sorting meetings, the control flow is as follows:
- The user issues a sort command with the desired attribute and optional reverse flag.
- The
UIcalls theQuickContactsParserthroughLogicManagerto initiate aSortMeetingCommandParserobject. - The
SortMeetingCommandParserparses the command and creates aSortMeetingCommandobject. - The
SortMeetingCommandis executed, and the correctComparatorfor the specified attribute is applied to theModelobject’ssortFilteredMeetingListmethod. -
LogicManagerreturns aCommandResultto theUIwith a success message indicating the attribute by which the meetings have been sorted.
Below is the Sequence Diagram:

Light Theme
The current theme is stored as a boolean inside GuiSettings, which is stored inside UserPrefs. Clicking the button toggles the boolean and removes the current stylesheet (eg. LightTheme.css/DarkTheme.css) and adds the opposite stylesheet to the scene.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
This sections describes the user requirements we intend to address with QuickContacts.
Target User Profile
QuickContacts is designed for users with busy schedules of meeting people.
- need to manage a large number of contacts and meetings
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition
QuickContacts allows users to manage contacts and meetings faster than a typical mouse/GUI-driven application.
User stories
Priority levels:
- High (must have) -
* * * - Medium (nice to have) -
* * - Low (unlikely to have) -
*
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * |
new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * |
user | add a new person | |
* * * |
user | delete a person | remove entries that I no longer need |
* * * |
user | find a person by name | locate details of persons without having to go through the entire list |
* * |
user | hide private contact details | minimize chance of someone else seeing them by accident |
* |
user with many persons in the contact book | sort persons by name | locate a person easily |
* |
user | Find a person by tag | I can filter the contacts by tags |
* |
user | Sort by tag priority | I can find the most important contacts |
* |
user | Assign tag priority | |
* |
user | Retrieve deleted contacts | |
* |
user | Set a date for deletion of contacts | Remove the contacts automatically |
* |
user | Add a contact | Store my contact in app |
* |
user | Delete a contact | Remove unwanted contacts |
* |
user | Edit a contact | Change details of existing contacts |
* |
user | Assign tag to contact | Categorise my contacts |
* |
user | Use the help command | To see available commands |
* |
power user | Assign shortcuts to different actions | I can cut down on the time taken to type |
* |
User with many connections | Export my contacts | I can share my contacts easily |
* |
User with many connections | Copy the details of my contacts | I can share my contacts easily |
* |
User with many existing contacts | Import my contacts automatically | I don't have to spend too much time creating contacts one by one |
* |
User with many meetups with people | Sort meetings based on the date and time | I can prioritize my time well |
* |
Busy user with many meetups | Receive notifications about meetups with contacts | I won't be late for meetups |
* |
User with many meetups with people | Create a meeting | Schedule a meeting |
* |
User with many meetups with people | Edit a meeting | Change meeting details |
* |
User with many meetups with people | Delete a meeting | Remove cancelled or completed meetings |
* |
User with many meetups with people | View all meetings | See in a glance the meetings that I have |
* |
User with many meetups with people | View meeting details | Understand what my meeting is about |
* |
Users with meetings | Add a reminder to meeting | So I do not forget the meeting |
* |
Users with meetings | Edit reminder of meeting | Change how frequent my reminders are |
* |
Users with meetings | Delete a reminder | So I am not spammed with reminders |
* |
Users with many meetings | Tag meeting | Organize they types of meetings |
* |
User who are very familiar with the keyboard | Add custom keybinds | So that I am faster at organizing contacts |
* |
User with many meetings | See how many days left to a meeting | I don't forget to attend one |
* |
User in a hurry | Undo previous action up to 3 previous actions | I can be fast and a bit sloppy without worrying |
* |
User who use the app for a long time | Set a reminder to tag people | In future I can better organize people |
* |
User who forget what is in contacts | Ask if person/meeting still relevant | So that the contact remain relatively clean |
* |
User assign name to priority tag | Customise the tags | I can remember more easily who is ranked higher |
Use cases
For all use cases below, the system is QuickContacts and the Actor is the user, unless specified otherwise.
Use case: UC1 - Add a contact
MSS:
- User requests to add a contact.
-
QuickContactsadds that contact. -
QuickContactsshows new contact in list.Use case ends.
Extensions:
- 1a. Input for a required field is illegal.
- 1a1.
QuickContactsprompts user with an error message. - Use case resumes at step 1.
- 1a1.
Use case: UC2 - Delete a contact
MSS:
- User requests to list contacts.
-
QuickContactsshows a list of contacts. - User requests to delete a specific contact in the list.
-
QuickContactsdeletes the contact.Use case ends.
Extensions:
- 2a. The list is empty.
-
QuickContactsreturns an empty list. - Use case ends.
-
- 3a. Index for the contact to be deleted is invalid.
-
QuickContactsprompts user with an error message. - Use case resumes from step 3.
-
Use case: UC3 - Find a contact
MSS:
- User requests searches contact by name.
-
QuickContactsshows that person.Use case ends.
Extensions:
- 1a. Input for a required field is illegal.
- 1a1. Show error message.
- Use case continues at step 1.
Use case: UC4 - Edit an existing contact’s details
MSS:
- User requests to edit a contact.
-
QuickContactsshows the contact with the updated details.Use case ends.
Extensions:
- 1a. Input for a field is illegal.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Contact cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC5 - User want to list all
MSS:
- User requests to list.
-
QuickContactsshows all the person and meetings.Use case ends.
Extensions:
- 1a. list is empty.
- Use case ends.
Use case: UC6 - User wants to clear everything
MSS:
- User requests to
clear. -
QuickContactsdeletes all contacts and meetings.Use case ends.
Use case: UC7 - User wants to exit
MSS:
- User requests to exit.
-
QuickContactscloses.Use case ends.
Use case: UC8 - Add a meeting
MSS:
- User requests to add a meeting.
-
QuickContactsadds that meeting. -
QuickContactsshows new meeting in list.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case resumes at step 1.
Use case: UC9 - Delete a meeting
MSS:
- User requests to list meetings.
-
QuickContactsshows a list of meetings. - User requests to delete a specific meeting in the list.
-
QuickContactsdeletes the meeting.Use case ends.
Extensions:
- 2a. The list is empty.
- Use case ends.
- 3a. The given index is invalid.
- 3a1.
QuickContactsshows an error message. - Use case resumes at step 2.
- 3a1.
Use case: UC10 - Edit a meeting
MSS:
- User requests to edit a meeting.
-
QuickContactsshows the meeting with the updated details.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meeting cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC11 - Sort by meeting attribute
MSS:
- User wants to sort by a meeting attribute.
-
QuickContactssorts the original list by order requested by user. -
QuickContactsshows the sorted list.
Use case: UC12 - Export Contacts
MSS:
- User requests to export contacts.
-
QuickContactsshows the exported contacts.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case resumes at step 1.
- 1a. Person index not given.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Person index cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC13 - Import Contacts
MSS:
- User requests to import contacts.
-
QuickContactsimports the meetings and updates the view.Use case ends.
Extensions:
- 1a. Contacts format malformed.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Contacts not provided.
- 1b1. Show error message.
- Use case continues at step 1.
- 1c. Duplicate contact without user indicating force import.
- 1c1. Show error message.
- Use case continues at step 1.
- 1d. User indicates force import.
- All contacts imported.
- Use case ends.
Use case: UC14 - Export Meetings
MSS:
- User requests to export meetings.
-
QuickContacts shows the exported meetings.
Use case ends.
Extensions:
- 1a. Meeting index not given.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meeting index cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC15 - Import Meetings
MSS:
- User requests to import meetings.
-
QuickContacts imports the meetings and updates the view.
Use case ends.
Extensions:
- 1a. Meetings format malformed.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meetings not provided.
- 1b1. Show error message.
- Use case continues at step 1.
- 1c. Duplicate meeting without user indicating force import.
- 1c1. Show error message.
- Use case continues at step 1.
- 1d. User indicates force import.
- All meetings imported.
- Use case ends.
Use case: UC16 - Mark Meetings as Done
MSS:
- User marks meetings as done.
-
QuickContacts updates meetings and updates the view.
Use case ends.
Extensions:
- 1a. Meeting index not found.
- 1a1. Show error message.
- 1b. Meetings not provided.
- 1b1. Show error message.
Use case ends.
Use case: UC17 - View Pending Meetings
MSS:
- User requests to view pending meetings.
-
QuickContacts displays meetings that are not marked as done and are in the future.
Use case ends.
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 1000 persons 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.
- Can support 1000 meetings with same amount of lag as 10 meeting.
- Commands should be intuitive to not technical people.
- Should be clear that meeting and people are 2 separate things.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Meetings: Important dates with a duration and a place
- Find: Searches by name field, case-insensitive, match all matching words individually
- GUI: Graphic User Interface
- MSS: Main Success Scenario
- OS: Operating System
- Java: Programming Language by SUN Oracle
- CLI: Command Line Interface
- LinkedList: Data structure that consists of nodes that contain data and a reference to the next node
- JSON: Stands for JavaScript Object Notation and it is a file format used for storing and transmitting data in attribute-value pairs and arrays.
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 contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Deleting a contact
-
Deleting a contact while all contacts are being shown
-
Prerequisites: List all contacts using the
listcommand. Multiple contacts in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete,delete x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Creating a meeting
-
Creating a meeting with a contact:
-
Prerequisites: Contact
Alex Yeoexists in QuickContacts. -
Test case:
addm m/Lunch with Alex dt/2003 15:00 p/Alex Yeo
Expected: New meeting withAlex Yeoon 20 March (of the current year) at 3PM is created, and it is displayed in the meetings list. -
Test case:
addm m/Lunch with Alex dt/2003 25:00 p/Alex Yeo l/The Deck des/Weekly catch-up
Expected: Meeting is not created since25:00is an invalid time. Error details shown in the status message. Status bar remains the same.
-
-
Creating a meeting without a contact:
-
Test case:
addm m/Dinner at home dt/2003222
Expected: New meeting is created for200322(20 March 2022). -
Test case:
addm m/Dinner at home
Expected: Meeting is not created as a date(and time) is required. Error details shown in the status message. Status bar remains the same.
-
Saving data
-
To simulate data file is not found:
-
Prerequisite:
QuickContactsis currently not running and the data files have been generated. -
Rename the file
quickcontacts.jsonin the same directory toquickcontacts.json.backup. -
Launch
QuickContacts.
Expected:
QuickContactslaunches normally and re-generates the sample default data. -
-
To simulate data file is corrupted:
-
Prerequisite:
QuickContactsis currently not running and the data files have been generated. -
Open
quickcontacts.jsonwith a text editor, add a few random characters and save it. -
Launch
QuickContacts.
Expected: A warning message will be displayed and
QuickContactswill start from an empty data file. -
-
To simulate restoring data from a backup data file:
-
Prerequisite:
QuickContactsis currently not running and the data files have been generated and you have the backup file ready. Assume that the backup file is namedquickcontacts.json.backup. -
Delete
quickcontacts.jsonfrom the directory that containsquickcontacts.jar. -
Move
quickcontacts.json.backupinto the same directory asquickcontacts.jar. -
Rename
quickcontacts.json.backuptoquickcontacts.json. -
Launch
QuickContacts.
Expected:
QuickContactswill launch normally with the data restored from the backup. -
Command summary
| Action | Format, Examples |
|---|---|
| Create a contact |
add n/CONTACT_NAME [p/CONTACT_PHONE_NUMBER] [e/CONTACT_EMAIL] [a/CONTACT_ADDRESS] [t/CONTACT_TAG]... e.g., add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague
|
| Reset all data | clear |
| Delete a contact |
delete INDEXe.g., delete 3
|
| Edit a contact |
edit INDEX [n/CONTACT_NAME] [p/CONTACT_PHONE_NUMBER] [e/CONTACT_EMAIL] [a/CONTACT_ADDRESS] [t/CONTACT_TAG]...e.g., edit 2 n/James Lee e/jameslee@example.com
|
| Find a contact |
find KEYWORD [MORE_KEYWORDS]e.g., find James Jake
|
| List all contacts | list |
| Help | help [COMMAND_WORD] |
| Exit the app | exit |
| Create a meeting | addm m/MEETING_TITLE dt/MEETING_DATE_TIME [p/MEETING_ATTENDEE]... [l/MEETING_LOCATION] [des/MEETING_DESCRIPTION] |
| Edit a meeting | editm INDEX [m/MEETING_TITLE] [dt/MEETING_DATE_TIME] [p/MEETING_ATTENDEE]... [l/MEETING_LOCATION] [des/MEETING_DESCRIPTION] |
| Find a meeting |
findm KEYWORD [MORE_KEYWORDS] e.g, findm James Jake
|
| List all meetings | findm |
| Mark meeting as done |
mark m/INDEX [m/MORE_INDEXES]... |
| Mark meeting as not done |
unmark m/INDEX [m/MORE_INDEXES]... |
| View pending Meetings | pending |
| Delete a meeting |
delm INDEX e.g., delm 3
|
| Export a contact |
export p/INDEX [p/MORE_INDEXES]... e.g., export p/1 p/2 p/3
|
| Export a meeting |
exportm m/INDEX [m/MORE_INDEXES]... [start/MEETING_EXPORT_START_DATE] [end/MEETING_EXPORT_END_DATE] e.g., exportm m/1 m/2 m/3
|
| Import a contact | import VALID_JSON |
| Import a meeting | importm VALID_JSON |
| Sort meetings |
sortm SORT_FIELD [r] e.g., sortm dt/
|
Appendix: Planned Enhancements
-
Currently, the UI shows a blank area when an attribute is undefined for contacts and meetings.
Proposed Fix: Have a placeholder
No ATTRIBUTE definedfor each undefined attribute. -
Currently, once we define an attribute for a contact, we are unable to remove it.
Proposed Fix: Add a new command “deleteattribute” for this purpose. For example,
deleteattribute p/1 e/to remove email for a contact ordeleteattribute m/1 des/to remove description for a meeting.