Developer Guide
- Acknowledgements
- Introduction
- Setting up, getting started
- Design
- Implementation
- Documentation
- Logging
- Testing
- Configuration
- Dev-ops
- Appendix: Requirements
- Appendix: Glossary
- Appendix: Planned Enhancements
-
Appendix: Instructions for manual testing
- Launch and shutdown
- Adding a contact
- Editing a contact
- Finding contacts
- Listing contacts
- Removing a contact’s field
- Deleting a contact
- Clearing all contacts or tags
- Sorting contacts
- Viewing a contact’s detailed information
- Adding a project
- Editing a project
- Deleting a project
- Removing a project’s field
- Clearing all projects
- Sorting projects
- Assigning a contact to a project
- Unassigning a contact from a project
- Saving data
Acknowledgements
- This project is based on the AddressBook-Level3 project created by the SE-EDU initiative.
Introduction
This Developer Guide serves as documentation of the architecture and design of SOCket, an application for managing contacts and projects quickly using CLI (Command Line Interface), with some key implementation details of SOCKet’s features. The current version of SOCket is v1.4.
The Developer Guide is written to aid present and future developers of SOCket with understanding the architecture, design and non-trivial implementations of SOCket’s features. In doing so, this guide imparts the knowledge required for developers to further modify and extend the features and functionality of SOCket beyond its current state.
The code for SOCket is hosted on GitHub here.
Refer to the following section for how to set up and get started with SOCket.
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.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

Each of the four main components (also shown in the diagram above),
- 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
Shown below is the class diagram for 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
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 displaysPersonandProjectobject residing in theModel.
Logic component
The API of this component is specified in 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 theSocketParserclass 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
SocketParserclass 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 theSocketParserreturns 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.
Shown below is the activity diagram for how SOCket parses a user input:

Model component
The API of this component is specified in Model.java
Shown below is the class diagram for the Model component:

The Model component,
- stores the
Socketdata, i.e., allPersonobjects (contained in aUniquePersonListobject) and allProjectobjects (contained in aUniqueProjectListobject). - stores the
VersionedSocketdata, i.e.,Socketstates to restore, either toundoorredochanges - 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 the
Projectobjects as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Project>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)
Language and Tag lists in Socket, which Person references. This allows Socket to only require one Language/Tag object per unique language/tag, instead of each Person needing their own Language/Tag objects.
Storage component
The API of this component is specified in Storage.java
Shown below is the class diagram for the Storage component:

The Storage component,
- can save both
Socketdata and user preference data in json format, and read them back into corresponding objects. - can save data on
Personmembers of aProjectand restore references to samePersonobjects inUniquePersonListupon readingSocketdata back into corresponding objects. - inherits from both
SocketStorageandUserPrefStorage, 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.socket.commons package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Undo/Redo feature
Implementation
This feature was implemented as proposed in AddressBook-Level3
The undo/redo mechanism is facilitated by VersionedSocket. It extends Socket with an undo/redo history, stored internally as an socketStateList and currentStatePointer. Additionally, it implements the following operations:
-
VersionedSocket#commit()— Saves the current ‘Socket’ state in its history. -
VersionedSocket#undo()— Restores the previous ‘Socket’ state from its history. -
VersionedSocket#redo()— Restores a previously undone ‘Socket’ state from its history.
These operations are exposed in the Model interface as Model#commitSocket(), Model#undoSocket() and Model#redoSocket() 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 VersionedSocket will be initialized with the initial Socket state, and the currentStatePointer pointing to that single Socket state.

Step 2. The user executes delete 5 command to delete the 5th person in ‘Socket’. The delete command calls Model#commitSocket(), causing the modified state of Socket after the delete 5 command executes to be saved in the socketStateList, and the currentStatePointer is shifted to the newly inserted Socket state.

Step 3. The user executes add n/David … to add a new person. The add command also calls Model#commitSocket(), causing another modified Socket state to be saved into the socketStateList.

Model#commitSocket(), so the Socket state will not be saved into the socketStateList.
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoSocket(), which will shift the currentStatePointer once to the left, pointing it to the previous Socket state, and restores Socket to that state.

currentStatePointer is at index 0, pointing to the initial Socket state, then there are no previous Socket states to restore. The undo command uses Model#canUndoSocket() 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:

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#redoSocket(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores Socket to that state.
currentStatePointer is at index socketStateList.size() - 1, pointing to the latest Socket state, then there are no undone Socket states to restore. The redo command uses Model#canRedoSocket() 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 Socket, such as list, will usually not call Model#commitSocket(), Model#undoSocket() or Model#redoSocket(). Thus, the socketStateList remains unchanged.

Step 6. The user executes clear, which calls Model#commitSocket(). Since the currentStatePointer is not pointing at the end of the socketStateList, all Socket 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.

The following activity diagram summarizes what happens when a user executes a new command:

Design considerations
Aspect: How undo & redo executes:
-
Alternative 1 (current choice): Saves the entire
Socket.- 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 person being deleted). - Cons: We must ensure that the implementation of each individual command are correct.
- Pros: Will use less memory (e.g. for
List Feature
Implementation
The list feature allows user to display a list of persons. The user can filter the list by tag or language. list filters the list by AND search. If no argument is given, then list by default displays all persons in SOCket.
The feature is mainly facilitated by the ListCommand class and with the help of Predicate classes.
ListCommand extends Command and implements the following operation:
-
ListCommand#execute()- Displays the list of persons in SOCket that contains the given keyword of each respective fields.
The ListCommandParser class is used to parse and verify the user input to create the list command.
Once the input is parsed by ListCommandParser, a list of keywords for each respective field is then used to create the respective Predicate class to check if any keyword matches the given field of a Person.
The Predicates relevant to ListCommand differ from FindCommand in the way that it looks for full keyword matches in Person(s). If no fields are given, list of persons will be update by PREDICATE_SHOW_ALL_PERSONS/ a true predicate.
Otherwise, this list of Predicate classes include:
ListCommandLanguagePredicateListCommandTagPredicate
This Predicate class will return True as long as any of the Predicate classes inside it returns True. The Predicate classes works using an AND search, persons will be shown in the resulting list only if all the keywords given should match to the Person.
The following sequence diagram shows how the list operation works:

Design considerations
Aspect: Filtering by other fields
- Initially considered list to not have additional arguments but as decided to filter through Language and Tag due to:
- Find currently does a partial keyword match, thus list allows user to have the option to do full keyword matches
- As language(s) and tag(s) are the only fields which can belong to more than one person, it makes sense to use list to do full keyword matches on these fields only.
Sort Feature
Implementation
The sort feature allows users to sort the list of persons and projects in the application.
The feature is facilitated by the SortCommand and SortProjectCommand classes.
They extend Command and implements the following operations:
-
SortCommand#execute()— Sorts the list of persons in the application. -
SortProjectCommand#execute()— Sorts the list of projects in the application.
The SortCommandParser and SortProjectCommandParser classes are used to parse the user input and create the respective commands.
The respective classes verify that the user input is valid and create the commands accordingly.
If no argument is provided, Persons will be sorted by name and Projects will be sorted by deadline by default.
The input is then passed to the sort function in UniquePersonList and UniqueProjectList respectively.
The sort makes use of a comparator that sorts the persons or projects by the category specified by the user.
If the person or project does not have that field, they are sorted at the back. If there are multiple persons or contacts where the field is empty, they are sorted by name.
The following sequence diagram shows how the sort operation works for persons (implementation is similar for projects):

Find Feature
Implementation
The find feature allows users to display a list of contacts from SOCket that contains the given keyword of each respective fields.
The feature is facilitated by the FindCommand class mainly but Predicate classes are also used.
FindCommand extends Command and implements the following operation:
-
FindCommand#execute()— Finds and displays the list of persons in the application that contains the given keyword of each respective fields.
The FindCommandParser class is used to parse & verify the user input to create the find command.
Once the input is parsed by FindCommandParser, a list of keywords for each respective field is then used to create a Predicate class that checks if any keyword matches the given field of a Person.
This list of Predicate classes include:
FindCommandAddressPredicateFindCommandEmailPredicateFindCommandLanguagePredicateFindCommandNamePredicateFindCommandPhonePredicateFindCommandProfilePredicateFindCommandTagPredicate
Each of the above Predicate class will return True as long as any keyword in the list of keywords matches any word in the respective field.
All the above Predicate classes will be enclosed inside a FindCommandPersonPredicate class.
This Predicate class will return True as long as any of the Predicate classes inside it returns True.
The Predicate classes works using an OR search, as long as a keyword matches any word in the respective field, that person will be shown in the resulting list from find command.
FindCommandPersonPredicate is used to enclosed all the other Predicate class as the updateFilteredPersonList for ModelManager class only accepts 1 Predicate<Person> class.
Find command now checks on all fields, but we cannot pass in each Predicate class for the different fields into updateFilteredPersonList without resetting the previous filtered list.
While it may be possible to modify updateFilteredPersonList to accept the multiple Predicate class without resetting the previous filtered list, we decided against it as:
- Heavy modification to
updateFilteredPersonListis required which is highly likely to cause many unintended bugs and even break the entire program. - Many other commands use
updateFilteredPersonListas well, changing the behavior ofupdateFilteredPersonListto suit find command would mean that we have to also change how the other commands useupdateFilteredPersonList.
If no argument is provided, an empty list will be shown.
The following sequence diagram shows how the find operation works:


(“Initializing Predicate for other fields” reference frame is omitted as it is just initialization of the other Predicate classes)
Design considerations
Aspect: AND search or OR search
- An AND search has been considered for find initially but ultimately dropped in favor of OR search due to the following reasons:
- List command already does an AND search. Though only on Tag & Language currently, it can be extended to include the other fields eventually, making find a duplicate command of list command should find command use AND search as well.
- We intend for find command to be a more broad search, getting all persons that matches just a keyword. This is to help users narrow down their search should they forgot the exact name of a contact they are looking for.
Aspect: Full keyword match or Partial keyword match
- We have also considered a partial match of the keyword (For example:
hankeyword will match field with the valuehans). However we decide to implement a full match due to the following reason:- Having partial match may bring out unintended matches as the possible range of results is broadened. We fear that doing a partial match may be too broad for find command to function as a way for users to narrow down their search.
Remove Feature
Implementation
The remove feature allows users to remove a given value in Person’s and Project’s respective fields.
The feature is facilitated by the RemoveCommand class and RemoveProjectCommand classes.
They extend Command and implement the following operations:
-
RemoveCommand#execute()— Removes the respective Person’s field value based on the given input. -
RemoveProjectCommand#execute()— Removes the respective Project’s field value based on the given input.
The RemoveCommandParser and RemoveProjectCommandParser classes are used to parse the user input and remove the value that matches to the existing value in the respective field using RemovePersonDescriptor and RemoveProjectDescriptor respectively.
RemovePersonDescriptor and RemoveProjectDescriptor objects are created and pass with the Index (parsed from the user input) into respective commands.
The respective classes verify that the user input is valid and create the commands accordingly.
If no argument is provided, an exception will be thrown. Otherwise, if only predicate is present, the corresponding field of the Person/Project will be emptied.
Design considerations
Remove a specific field value
- While an edit feature that allows users to add or remove field values can be useful in certain contexts, it may not be appropriate or necessary in all situations:
- If user decides to remove 1 out of many field values in a person’s tag field, user will have a difficult time to type all the must-have value. WIth remove feature, user just need to type out the tag that he/she wish to remove.
- Currently, edit feature for language field is cumulative, language will not be removed, so remove feature helps to resolve the issue on language removal.
Project feature:
Implementation
This feature allows users to create and track ongoing projects. Details of each Project are recorded as attributes of the Project, which include ProjectName, ProjectRepoHost, ProjectRepoName, ProjectDeadline, ProjectMeeting, and a Set<Person>, which stores the Person objects involved with the Project. Project objects are stored in a UniqueProjectList in Socket.
Any changes to Person objects that are associated with a Project object automatically updates the outdated Person object in the associated Project object (i.e., edit, remove, delete).
The following sequence diagram shows how updates are made to the associated Project object when updates are made to Person objects on execution of a DeleteCommand:

Step 1. The DeleteCommand#execute() method is called.
Step 2. The ModelManager#deletePerson(p) method of the ModelManager implementing the Model interface is then called.
Step 3. This calls the method Socket#removePerson(p), which:
- calls
UniquePersonList#remove(p)to delete the personpfrom theUniquePersonListpersons. - calls
UniqueProjectList#removeMemberInProjects(p)which removes any stored references to the deleted personpfrom theProjectobjects in theUniqueProjectListprojects.
Step 4. The execution of the DeleteCommand then continues, and the result is encapsulated as a CommandResult (not shown) and returned.
commitSocket() and creation of a CommandResult portions of the execution as they are not relevant to the discussion.
Updates to Person objects associated with a Project object through the other commands are handled similarly.
The following classes handle operations on Project objects:
-
XYZProjectCommand- represents a command operating onProjectobjects, i.e.,AddProjectCommand,EditProjectCommand, etc. -
XYZProjectCommandParser- parses the respectiveXYZProjectCommandthat operates onProjectobjects. -
AssignCommand,UnassignCommand- represent commands for assigning/unassigning aPersonobject to aProjectobject.
The JsonAdaptedProject class handles the reading/writing to storage for Project objects. It makes use of JsonAdaptedPerson to store the Person objects associated with the Project. Storage for Person objects associated with a Project object are stored in the .json file by making a copy of the data for the Person in the “persons” list in the “members” list under the respective Project object in the “projects” list.
When JsonSerializableSocket#toModelType is called to convert the stored data into a Socket object, the restored Person objects in the UniquePersonList are matched to the duplicate Person objects in the Project objects and the duplicate Person objects are replaced with the exiting objects in the UniquePersonList.
Design considerations:
Aspect: How Project objects are stored:
-
Alternative 1 (current choice): Stores the
Projectobjects with thePersonobjects in a single.jsonfile.- Pros: Fewer files to manage, simpler to write data to upon any changes to
Socket. - Cons: Corrupt data in “projects” will cause entire file to be discarded, deleting “persons” data.
- Pros: Fewer files to manage, simpler to write data to upon any changes to
-
Alternative 2: Stores the
Projectobjects with thePersonobjects in separate.jsonfiles.- Pros: Corrupt data in “projects” will only cause “projects” file to be discarded.
- Cons: More files to manage, harder to write data to upon any changes to
Socket.
Documentation
The Documentation guide covers how documentation is managed for SOCket.
Logging
The Logging guide covers how logging is used in SOCket.
Testing
The Testing guide covers types of test cases used in SOCket, as well as how to run them.
Configuration
The Configuration guide covers how certain properties of SOCket can be managed through the configuration file.
Dev-ops
The DevOps guide covers build automation and steps to create releases for SOCket.
Appendix: Requirements
Product scope
Target user profile:
- has a need to manage a significant number of contacts (peers, professors in NUS Computing)
- has a need to group and manage groups of contacts
- has a need to view the skills and proficiencies of contacts (programming languages, modules)
- has a need to access the GitHub profiles/repositories of contacts
- has a need to track deadlines and responsibilities associated with contacts
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: manage contacts faster than a typical mouse/GUI driven app, store information relevant to NUS Computing students (GitHub profile, repository, programming language proficiencies, modules taken), quickly find contacts that satisfy certain criteria (taken a particular module, in a group)
User stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I can… | 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 |
* * * |
student with many friends | save my friend’s details | easily contact them |
* * * |
student who likes to ask questions | save my professors’ details | easily contact them to ask questions |
* * * |
student with fast typing speed | use command based inputs to search for contacts | quickly pull out contacts without needing to spend time moving my mouse |
* * |
user | hide private contact details | minimize the chance of someone else seeing them by accident |
* * |
student involved in project work | search contacts belonging to a certain group | contact my groupmates easily |
* * |
student with many assignments | tag deadlines and responsibilities to my contacts | easily keep track of which tasks are more urgent and who is taking care of it |
* * |
organised user | group contacts into different groups | manage my contacts easily |
* * |
software engineering student with many SE projects | access the github repositories of my peers | easily keep track of the github repos that I’m involved and interested in |
* * |
student interested in hackathons | find students based on skills | form groups with them |
* * |
software engineering student | find repositories of group projects I am involved in | easily access team repositories |
* * |
student who is organised | sort all my peers’ contact information | have only one platform where I know my contacts are organized |
* * |
software engineering student | tag contacts with their skills | know what skills they have and can easily find those with a particular skill |
* * |
advanced user | use the shortcut keys | get things done more effectively |
* * |
busy software engineering student | create shortcuts to long commands | not type out long commands repeatedly to save time |
* * |
student constantly getting into new projects with other members | quickly remove tags of specific groups and delete contacts | not be flooded with too much irrelevant contacts which can cause accidental wrong contact |
* * |
software engineering student with many peers | save and access my peers’ github information | easily access their profiles and view their repositories |
Use cases
(For all use cases below, the System is the SOCket and the Actor is the user, unless specified otherwise)
Use case: UC01 - Add a contact
MSS:
- User requests to add a contact.
-
SOCket adds the contact.
Use case ends.
Extensions:
-
1a. There are no details provided.
-
1a1. SOCket shows an error message.
Use case resumes at step 1.
-
-
1b. There is no name provided.
-
1b1. SOCket shows an error message.
Use case resumes at step 1.
-
Use case: UC02 - Edit a contact
MSS:
- User requests to list contacts.
- SOCket shows a list of contacts.
- User requests to edit a specific contact’s details in the list.
- SOCket edits the contact’s details.
Extensions:
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. SOCket shows an error message.
Use case resumes at step 2.
-
-
3b. There are no details provided.
-
3b1. SOCket shows an error message.
Use case resumes at step 2.
-
-
3c. There are no tags provided.
-
3b1. SOCket removes all tags associated with the contact.
Use case ends.
-
-
3d. There are tag(s) provided.
-
3b1. SOCket removes existing tags associated with the contact and adds the tag(s) provided.
Use case ends.
-
Use case: UC03 Delete a contact
MSS:
- User requests to list contacts.
- SOCket shows a list of contacts.
- User requests to delete a specific contact in the list.
-
SOCket deletes the contact.
Use case ends.
Extensions:
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. SOCket shows an error message.
Use case resumes at step 2.
-
Use case: UC04 Sort contacts
MSS:
- User requests to list contact.
- SOCket shows a list of contacts.
- User requests to sort the list by a category.
-
SOCket sorts the contacts by that category and displays the sorted contact list.
Use case ends.
Extensions:
-
2a. The list is empty.
Use case ends.
-
3a. The given category is invalid.
-
3a1. SOCket shows an error message.
Use case resumes from step 2.
-
-
3b. No category is given.
-
3b1. SOCket sorts the list by name and displays the sorted list.
Use case ends.
-
Use case: UC05 Find contact(s)
MSS:
- User request to find a contact with the given keywords in their respective fields.
-
SOCket shows a list of contacts that contains any of the given keyword in their respective fields.
Use case ends.
Extensions:
-
1a. No contact matches any of the given keywords in their respective fields.
-
1a1. SOCket shows an empty list of contacts.
Use case ends.
-
-
1b. No keywords are given for all fields.
-
1b1. SOCket shows an empty list of contacts.
Use case ends.
-
Use case: UC06 Clear contacts/tag
MSS:
- User chooses to clear off group of contacts.
- SOCket requests for confirmation to delete the contacts.
- User confirms.
- SOcket deletes all the contacts.
Use case ends.
Extensions:
-
1a. All the given tags are present in SOCket.
- 1a1. SOCket request to delete all the contacts under the tags.
-
1b. Some given tags are not present in SOCket.
-
1b1. SOCket shows an error message, listing all the wrong tags.
-
1b2. SOCket request to delete all the contacts under the correct tags.
Use case resumes at step 2.
-
-
1c. All the given tag are not present in SOCket.
-
1c1. SOCket shows an error message, listing all the wrong tags.
-
1c2. SOCket requests for correct tags.
Steps 1c1-1c2 are repeated until a tag is entered correctly.
Use case resumes at step 2.
-
-
1d. No tag is provided.
-
1d1. SOCket request to delete all the contacts.
Use case resumes at step 2.
-
-
*a. At any time, User choose to cancel the operation.
-
*a1. SOCKet stops the operation.
Use case ends.
-
Use case: UC07 List contacts
MSS:
- User requests to list contacts.
- SOCket shows a list of contacts.
- User requests to list contacts by language(s) and tag(s).
-
SOCket shows a list of contacts with given language(s) and tag(s).
Use case ends.
Extensions:
-
3a. The given tag(s) or language(s) is invalid.
-
3a1. SOCket shows an error message.
Use case resumes at step 2.
-
-
3b. No contact matches the given language(s) or tag(s).
-
3b1. SOCket shows an empty list of contacts.
Use case resumes at step 2.
-
-
3c. No category is given.
Use case resumes at step 2.
Use case: UC08 Access Help page
MSS:
- User requests for help.
-
SOCket shows the help page.
Use case ends.
Use case: UC09 - Exit SOCket
MSS:
- User requests to exit SOCket.
-
SOCket exits.
Use case ends.
Use case: UC10 Hide contact details
MSS:
- User requests to list contact.
- SOCket shows a list of contacts.
- User requests to hide a category of a specific contact.
-
SOCket hides the specific category of that user.
Use case ends.
Extensions:
-
2a. The list is empty.
Use case ends.
-
3a. The given category is invalid.
-
3a1. SOCket shows an error message.
Use case resumes at step 2.
-
-
3b. The contact does not have that category.
-
3b1. SOCket shows an error message.
Use case resumes at step 2.
Use case ends.
-
Use case: UC11 Using shortcut command
MSS:
- User binds a command to a given keyword of their choice.
- SOCket shows a message to confirm shortcut key created.
- User types the keyword bound to the command.
- SOCket will execute the command. Use case ends.
Extensions:
-
3a. Command bounded to the keyword is not valid.
-
3a1. SOCket shows an error message.
Use case ends.
-
Use case: UC12 Access peer GitHub information
MSS:
- User requests to list contact.
- SOCket shows a list of contacts.
- User requests to view a specific contact’s github information.
-
SOCket opens the contact’s github profile in a browser.
Use case ends.
Extensions:
-
2a. The list is empty.
Use case ends.
-
3a. The contact does not have github information.
Use case resumes at step 2.
Use case: UC13 Undo recent changes
MSS:
- User requests to undo changes.
-
SOCket undoes changes.
Use case ends.
Extensions:
-
1a. No changes exist.
-
1a1. SOCket shows an error message.
Use case ends.
-
Use case: UC14 Redo recent undone changes
MSS:
- User requests to restore recent undone changes.
-
SOCket restores undone changes.
Use case ends.
Extensions:
-
1a. No undone changes exist.
-
1a1. SOCket shows an error message.
Use case ends.
-
Use case: UC15 Tagging a contact
MSS:
- User find contact(s) (UC05) they wish to tag.
- User tags the list of contacts currently shown with a tag name.
-
SOCket tags all contacts in the list currently shown, displays all contacts with the given tag name to the user.
Use case ends.
Use case: UC16 Set deadlines & responsibilities
MSS:
- User has a team project and creates an event.
- SOCket creates the event.
- User request to groups all the team members contact under the event created.
- SOCket groups the contacts together.
- User enters a deadline date to each milestone of the project.
- SOCket allocates the date to respective milestone.
- User chooses to give role to each team members.
-
SOCket assigned the given roles to respective team members.
Use case ends.
Extensions:
-
5a. SOCket detects a syntax error in the entered date.
-
5a1. SOCket shows an error message.
Use case resume at step 6 when the date entered is correct.
Use case resumes at step 2.
-
Use case: UC17 Removing tag/language(s)
MSS
- User found that he/she has place a wrong tag to a person.
- User request to remove the specific tag.
-
SOCket find the person and removes the tag associated to it.
Use case ends.
Extensions
-
2a. SOCket detects that user inputs an empty field after the tag prefix.
-
2a1. SOCket removes all tags associated to it.
Use case ends.
-
Use case: UC18 Viewing a person’s detail
MSS
- User find contact(s) (UC05) he/she wishes to view.
- SOCket lists out all the contact associated to the category.
- User wishes to view the first contact in the list.
-
SOCket displays all the person’s information at the detail display window.
Use case ends.
Use case: UC19 Sorting project list
Similar to UC04 Sort Contacts, except,
- the list being sorted is the list of projects instead of contacts
- the default sort when no category is provided is by the deadline of the project instead of the name.
Use case: UC20 Assigning a member from a project
- User requests to add a contact to a project.
-
SOCket adds the contact to the project.
Use case ends.
Extensions
- 2a. The chosen contact is already assigned to the project.
-
2a1. SOCket shows an error message.
Use case ends.
-
- 2b. The chosen project does not exist.
-
2b1. SOCket shows an error message.
Use case ends.
-
- 2c. The chosen contact does not exist.
-
2c1. SOCket shows an error message.
Use case ends.
-
Use case: UC21 Unassigning a member from a project
- User requests to remove a member from a project.
-
SOCket removes the member from the project.
Use case ends.
Extensions
- 2a. The chosen member is not assigned to the project.
-
2a1. SOCket shows an error message.
Use case ends.
-
- 2b. The chosen project does not exist.
-
2b1. SOCket shows an error message.
Use case ends.
-
Use case: UC22 - Add a project
Similar to UC01 Add a contact, except,
- A projects is added instead of contact.
- Only meeting date is an optional field, all other fields are compulsory.
Use case: UC23 Delete a project
Similar to UC03 Delete a contact, except,
- a list of projects is shown instead of contacts.
- a project is deleted instead of a contact.
Use case: UC24 Edit a project
Similar to UC02 Edit a contact, except,
- a list of projects is shown instead of contacts.
- a project’s details are edited instead of a contact’s details.
Use case: UC25 Removing a project’s fields
Similar to UC17 Removing tag/language(s), except,
- a project’s details are removed instead of tag/languages(s)
Use case: UC26 Clear projects
Similar to UC06 Clear contacts/tag, except,
- all projects are cleared instead of all contacts.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11or above installed. - Should work on 64-bit environments.
- Should be able to hold up to 1000 contacts without a noticeable sluggishness in performance for typical usage.
- Should be able to hold up to 100 projects 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.
Appendix: Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
-
GitHub profile: GitHub username e.g.
chia-yh -
GitHub repository: repository path e.g.
AY2223S2-CS2103T-T12-4/tp
Appendix: Planned Enhancements
- The current
VALIDATION_REGEXfor validating theNamefield is flawed, and does not consider names with/,-or.valid.- Valid
Namefields:Hubert Blaine Wolfeschlegelsteinhausenbergerdorff SrAlex Yeoh2
- Invalid
Namefields:Balakrishnan s/o NagamuthuChien-Ming WangS. R. Nathan
We plan to update the
VALIDATION_REGEXto also allow other possible names including, but not limited to, those under “InvalidNamefields” above. TheVALIDATION_REGEXcurrently does not restrictNamelength to allow for contacts with long names. These cases are handled in the UI by allowing the contact list to be scrollable, and wrapping long names in the detail panel. - Valid
- The current
VALIDATION_REGEXfor validating thePhonefield is flawed, and does not consider phone numbers with+,-, `,(, or)` valid.- Valid
Phonefields:99512345678
- Invalid
Phonefields:+65 1234567801234-012345(01234) 012345
We plan to update the
VALIDATION_REGEXto allow other possible phone numbers including, but not limited to, those under “InvalidPhonefields” above, as well as limiting the length of a validPhonefield to follow the longest conventionally accepted phone number. - Valid
- The current
VALIDATION_REGEXfor validatingLanguagefields is flawed, and does not consider languages with.or ` ` valid.- Valid
Languagefields:JavaC++C#C--
- Invalid
Languagefields:NET.DataText Executive Programming Language
We plan to update the
VALIDATION_REGEXto allow other possible languages including, but not limited to, those under “InvalidLanguagefields” above. This entails enhancements such as allowing aLanguagefield to consist of multiple words in the case that users choose to store the full name of a language instead of its acronym, or names of languages with multiple words without a conventionally accepted acronym, as well as allowing.in theLanguagefield. - Valid
- The current restrictions allow for adding a
Projectwith an overdueProjectDeadlineand/orProjectMeetingfield, without any indication that the deadline or meeting has passed. As users may want to keep the details of finished projects or meetings for posterity, we plan on continuing to allow theProjectDeadlineandProjectMeetingfields to be set to past date and time, however, further checks will be added when setting theProjectDeadlineorProjectMeetingfields to notify users when setting a date and time that has already passed, showing an additional message:The project deadline has already passed.orThe project meeting has already passed. - The current
Projectonly allows users to set a singleProjectMeeting, which could be problematic in the case that users would like to store the details of several meetings in advance, as opposed to just the upcoming meeting. We plan to enhance this feature to allow users to set severalProjectMeetingfields for aProject, to enable users to manage more meetings for aProject, such as future meetings past the upcoming meeting, as well as keep a record of previous meetings if such a need arises. - The current UI makes use of a horizontal scroll bar to handle the interaction of overflowing text with tags in the contact panel. To enhance the user experience, we plan to only display the tag count initially. If the user chooses to view a specific contact, the contact card will then expand to show the full list of tags associated with that contact.
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.
-
Adding a contact
-
Adding a contact to the contact list
-
Test case:
add n/John Doe p/98765432 g/johndoe l/Python
Expected: Adds a contact with the nameJohn Doeand the provided phone, GitHub profile, and language details. -
Test case:
add n/John Doe
Expected: Adds a contact with the nameJohn Doeand no other details. -
Test case:
add n/John Doe p/abc
Expected: No contact is added. An error message is shown as an invalid phone number was given. An error is logged in the console. -
Other incorrect add commands to try:
add,add John DoeExpected: No contact is added. An error message is shown as an invalid command was given. An error is logged in the console.
-
Editing a contact
-
Editing a contact while all contacts are being shown
-
Prerequisites: List all contacts using the
listcommand. At least one contact in the list. -
Test case:
edit 1 n/Dohn Joe
Expected: First contact in the list is edited with the nameDohn Joe -
Test case:
edit 1 t/friend t/owesmoney
Expected: Existing tags of the first contact in the list are replaced with the tagsfriendandowesmoney -
Test case:
edit 1 l/Python
Expected: ThePythonlanguage is added to the existing languages of the first contact. An error is logged in the console. -
Test case:
edit 1
Expected: No contact is edited. An error message is shown as no fields to edit were provided. An error is logged in the console. -
Test case:
edit 0
Expected: No contact is edited. An error message is shown as an invalid index was given. An error is logged in the console. -
Other incorrect edit commands to try:
edit,edit John Doe
Expected: No contact is edited. An error message is shown as an invalid command was given.
-
Finding contacts
-
Finding contacts while all contacts are being shown.
-
Test case:
find n/alex
Expected: Contacts with name that containsalexis shown. -
Test case:
find l/Java
Expected: Contacts with language that containsJavais shown. -
Test case:
find n/alex t/neighbours
Expected: Contacts with namealexor tagneighboursis shown. -
Test case:
find l/
Expected: An empty contact list is shown. -
Test case:
find
Expected: An empty contact list is shown. -
Test case:
find n/next n/alex
Expected: Same list of contacts as find test case 1i is shown as only the value of the last occurrence of a prefix is used.
-
-
Listing contacts while some contacts are being shown.
-
Prerequisites: Filter the contact list with
findorlistcommand. -
Test case:
find n/alex
Expected: All contacts with name that containsalexin SOCket (including those not shown before executingfind n/alex) is shown. -
Test case:
find l/Java
Expected: All contacts with language that containsJavain SOCket (including those not shown before executingfind l/Java) is shown. -
Test case:
find n/alex t/neighbours
Expected: All contacts with namealexor tagneighboursin SOCket (including those not shown before executingfind n/alex t/neighbours) is shown. -
Test case:
find l/
Expected: An empty contact list is shown. -
Test case:
find
Expected: An empty contact list is shown. -
Test case:
find n/next n/alex
Expected: Same list of contacts as find test case 2ii is shown as only the value of the last occurrence of a prefix is used.
-
Listing contacts
- Listing contacts while all contacts are being shown.
-
Prerequisites: At least one contact in the list.
-
Test case:
list t/friend
Expected: Contacts tagged withfriendis shown. -
Test case:
list l/Java
Expected: Contacts with languageJavais shown. -
Test case:
list t/friend l/Java
Expected: Contacts with tagfriendand languageJavais shown. -
Test case:
list l/
Expected: An error is message is shown as an invalid syntax for language is given. -
Test case:
list 12345
Expected: Same list of contacts is shown as this would be regarded as alistcommand.
-
- Listing contacts while some contacts are being shown.
-
Prerequisites: Filter the contact list with
findorlistcommand. At least one contact in the list. -
Test case:
list
Expected: All contacts from the unfiltered list is shown. -
Test case:
list t/friend
Expected: Contacts tagged withfriendin the filtered list is shown.
-
Removing a contact’s field
- Removing a contact’s field while all contacts are being shown
-
Prerequisites: At least one contact in the shown list.
-
Test case:
remove 1 l/
Expected: The language field of the first contact is removed. Language field in the person detail panel becomes empty. -
Test case:
remove 1 l/ t/
Expected: The language and tag field of the first contact are removed. Language and tag field in the person detail card becomes empty. -
Test case:
remove 1 t/friends
Expected: The language field of the first contact is removed only if its tag name previously wasfriends. Otherwise, an error message is shown as the field does not exist in the SOCKet. -
Test case:
remove 0 t/
Expected: No contact field is removed. An error message is shown as the given index is invalid. An error is logged in the console. -
Test case:
remove 0
Expected: No contact field is removed. An error message is shown as the given syntax is invalid. An error is logged in the console.
-
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.
-
Clearing all contacts or tags
-
Clearing all contacts or contacts associated with the given tag(s) while all contacts are being shown
-
Test case:
clear
Expected: All contacts are cleared. -
Test case:
clear t/
Expected: All contacts are cleared. -
Test case:
clear t/friendsExpected: Contacts with tagfriendsare cleared. -
Test case:
clear t/enemyExpected: If there are no contact with the tagenemy, no contact is cleared. An error message is shown as no such tag was found in the SOCket.
-
Sorting contacts
- Sorting contacts while all contacts are shown
- Prerequisites: At least two contacts in the list.
- Test case: ‘sort’
Expected: Contacts are sorted by name in alphanumerical order. - Test case: ‘sort name’
Expected: Contacts are sorted by name in alphanumerical order. - Test case: ‘sort address’
Expected: Contacts are sorted by address in alphanumerical order. Contacts without an address are at the back. - Other categories to try: ‘phone’, ‘email’, ‘github’
Expected: Contacts are sorted by the given category in alphanumerical order. Contacts without the given category are at the back. - Test case: ‘sort invalid’
Expected: An error message is shown as an invalid category was given. An error is logged in the console.
Viewing a contact’s detailed information
-
Viewing a contact’s detail while all the contacts are being shown
-
Prerequisites: At least one project in the list.
-
Test case:
view 1
Expected: Detailed information of the first contact is displayed in the person detail panel. -
Test case:
view 1 t/
Expected: No contact is displayed in the person details panel. An error message is shown as an invalid command was given. -
Test case:
view 0
Expected: No contact is displayed in the person details panel. An error message is shown as an invalid index was given. An error is logged in the console.
-
Adding a project
- Adding a project to the project list.
-
Prerequisites: No project in the list named
Project 1,Project 2,Project 3orProject 4. -
Test case:
addpj n/Project 1 h/project-1 r/ProjectOne d/29/04/22-0900 m/24/03/22-1400
Expected: Project with the project nameProject 1, repo hostproject-1, repo nameProjectOne, deadline29/04/22-0900& meeting24/03/22-1400is added to the project list. -
Test case:
addpj n/Project 2 h/project-1 r/ProjectOne d/29/04/22-0900 m/24/03/22-1400
Expected: Project with the project nameProject 2, repo hostproject-1, repo nameProjectOne, deadline29/04/22-0900& meeting24/03/22-1400is added to the project list. -
Test case:
addpj n/Project 3 h/project-1 r/ProjectOne d/29/04/22-0900
Expected: Project with the project nameProject 1, repo hostproject-1, repo nameProjectOne& deadline29/04/22-0900is added to the project list. -
Test case:
addpj n/Project 4 h/project-4 r/ProjectThree
Expected: No project is added to the project list as deadline value is missing.
-
Editing a project
- Editing a project while all projects are being shown
-
Prerequisites: At least one project in the list.
-
Test case:
editpj 1 n/Project Bravo
Expected: First project in the list is edited with the project nameProject Bravo -
Test case:
editpj 1 r/BravoRepo
Expected: Existing repo name of the first project in the list are replaced with the repo nameBravoRepo -
Test case:
editpj 1
Expected: No project is edited. An error message is shown as no fields to edit were provided. An error is logged in the console. -
Test case:
editpj 0
Expected: No project is edited. An error message is shown as an invalid index was given. An error is logged in the console. -
Other incorrect edit commands to try:
editpj,editpj Project Alpha
Expected: No project is edited. An error message is shown as an invalid command was given.
-
Deleting a project
-
Deleting a project while all projects are being shown
-
Prerequisites: At least one project in the shown list.
-
Test case:
deletepj 1
Expected: First project is deleted from the list. Details of the deleted project shown in the status message. Timestamp in the status bar is updated. -
Test case:
deletepj 0
Expected: No project is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
deletepj,deletepj x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Removing a project’s field
- Removing a project while all projects are being shown
-
Prerequisites: At least one project in the shown list.
-
Test case:
removepj 1 h/
Expected: First project repo host field is removed. Repo host in the project card becomesNot Available. -
Test case:
removepj 1 h/ r/
Expected: First project repo host and repo name fields are removed. Repo host and Repo name in the project card becomesNot Available. -
Test case:
removepj 1 r/first-project
Expected: First project repo name field is removed only if its repo name previously wasfirst-project. Otherwise, an error message is shown as the field does not exist in the project. -
Test case:
removepj 0 h/
Expected: No project field is removed. An error message is shown as the given index is invalid. An error is logged in the console. -
Test case:
removepj 0
Expected: No project field is removed. An error message is shown as the given syntax is invalid. An error is logged in the console.
-
Clearing all projects
- Clearing all projects in the list.
-
Test case:
clearpjExpected: All projects are cleared. -
Test case:
clearpj 123Expected: All projects are cleared. -
Test case:
clearpj h/Expected: All projects are cleared.
-
Sorting projects
- Sorting projects while all projects are being shown
- Prerequisites: At least two projects in the list.
- Test case: ‘sortpj’
Expected: Projects are sorted by deadline in chronological order. Projects without a deadline are at the back. - Test case: ‘sortpj name’
Expected: Projects are sorted by name in alphanumerical order. - Test case: ‘sortpj reponame’
Expected: Projects are sorted by repo name in alphanumerical order. Projects without a repo name are at the back. - Other categories to try: ‘repohost’, ‘deadline’, ‘meeting’
Expected: Projects are sorted by the given category in alphanumerical order. Projects without the given category are at the back. - Test case: ‘sortpj invalid’
Expected: Projects are not sorted. An error message is shown as an invalid category was given. An error is logged in the console.
Assigning a contact to a project
- Assigning a person contact to a project while all contacts & projects are being shown.
-
Prerequisites: At least one contacts & exactly two project in their shown list.
-
Test case:
assign 1 1
Expected: First contact in the contact list is assigned to the first project in the project list. -
Test case:
assign 1 3
Expected: First contact in the contact list is not assigned to any project in the project list. An error message is shown as the index provided for the project list is invalid. -
Test case:
assign a 1
Expected: An error message is shown as the given syntax is invalid. -
Test case:
assign 1 b
Expected: An error message is shown as the given syntax is invalid.
-
Unassigning a contact from a project
- Unassigning a contact from a project while all projects are being shown
- Prerequisites: At least one project with an existing contact named ‘Amy Bee’ assigned to the first project
- Test case:
unassign 1 n/Amy Bee
Expected: Amy Bee is unassigned from the first project. - Test case:
unassign 1 n/Bob Choo'
Expected: No contact is unassigned from the first project. An error message is shown as the contact is not assigned to the project.
Saving data
-
Dealing with missing/corrupted data files
- Prerequisites: A
.jsondata file containing some data -
Test case: Corrupted
.jsonfileOpen the
.jsonfile with a text editor and change any field to an invalid value (e.g. change a"phone"field toabc). Launch SOCket.Expected: SOCket starts with no data. An error is logged in the console.
- Prerequisites: A