Developer Guide
- Design
- Implementation
- Acknowledgements
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Appendix: Planned enhancements
Design

.puml
files used to create diagrams in this document are in the docs/diagrams
folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the app.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of classes Main
and MainApp
) is in charge of the app launch and shut down.
- At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
- At shut down, it shuts down the other components and invokes cleanup methods where necessary.
The bulk of the app’s work is done by the following four components:
-
UI
: The UI of the app. -
Logic
: The command executor. -
Model
: Holds the data of the app in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
Commons
represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
(Remark: The overlapping triangles into UiPart
are all class inheritance triangles (limitation of PlantUML).)
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, ContactListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysContact
object residing in theModel
.
The CommandBox
part keeps a reference to a CommandBoxHistory
object, which stores the history of entered commands, allowing for the functionality of navigating to previous commands using the up/down arrow keys within the CommandBox
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("delete 1 3 5")
API call as an example.
How the Logic
component works:
- When
Logic
is called upon to execute a command, it is passed to anInputParser
object which in turn creates a parser that matches the command (e.g.,DeleteCommandParser
) and uses it to parse the command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,DeleteCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to delete a contact). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
InputParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddCommand
) which theInputParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the contacts data i.e., all
Contact
objects (which are contained in aUniqueContactList
object). - stores the currently ‘selected’
Contact
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Contact>
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
Settings
object that represents the user’s preferences. This is exposed to the outside as aReadOnlySettings
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Storage component
API : Storage.java
The Storage
component,
- can save both contacts data and user preference data in JSON format, and read them back into corresponding objects.
- inherits from both
ContactsStorage
andSettingsStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the swe.context.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Add feature
The add feature is facilitated by ModelManager
and implements Model
.
The following sequence diagram shows how the add command works:
It adds an contact by calling Model#addContact
, which adds the newly created contact into the UniqueContactList
.
The following activity diagram summarises what happens when a user executes a new command.
Filter feature
The following sequence diagram shows how the filter command works:
It filters contacts by calling Model#setContactsFilter
with a ContainsTagPredicate predicate
as argument, which sets the predicate
on the list of contacts in the ModelManager
.
Maintaining sorting while supporting filtering
The contact list is automatically kept in a constantly sorted state by leveraging SortedList
from the JavaFX Collections library. Since the class works with ObservableList
s, which the Model’s Contacts
also utilises, we are able to leverage this class more easily.
The Model obtains an unsorted, unmodifiable list from Contacts
and wraps it in a SortedList
. We specify an AlphabeticalComparator
to define our own alphabetical sorting order, which takes capitalization into account. This facilitates the intended propagation of changes from the nested list to the sorted list.
For operability with the find and filter feature, this sorted list is further wrapped in a FilteredList
to limit the scope of what the user sees as needed. A dummy filter Predicate
which allows all contacts to pass is used as the default filter. It is this filtered list that the model stores in a field.
Edit feature
The edit feature is facilitated by ModelManager
and implements Model
.
It is similar in implementation to the add feature,
except it edits a contact by calling Model#updateContact
,
which replaces the old contact with the edited contact in the UniqueContactList
.
The following activity diagram summarises what happens when a user executes an edit command.
Navigating to previous commands
The feature of navigating between command history using the up/down arrow keys, is facilitated by CommandBoxHistory
. CommandBox
keeps a reference to a CommandBoxHistory
object which stores the history of entered commands.
CommandBoxHistory
stores a list of commands, which behaves externally as if its last element is always the empty string. This is so that the user can enter a new command when at the last position in the command history.
The following sequence diagram summarises what happens when the user presses the up arrow key to navigate to the previous command in history.
The behaviour is very similar when the user presses the down arrow key to navigate to the next command in history, so we omit the corresponding sequence diagram.
The following sequence diagram summarises what happens when the user successfully executes a new command, and this new command is stored in the command history.
The command is only stored in history if the execution of the command (by CommandExecutor
) is successful. The position in history is also reset to the last position (empty string) using CommandBoxHistory#resetPointer
.
Acknowledgements
- Libraries: JavaFX, Jackson, JUnit5
- App icon from McDo Design by Susumu Yoshida
- Some code adapted from http://code.makery.ch/library/javafx-8-tutorial/ by Marco Jakob
Appendix: Requirements
Product scope
Target user profile: NUS SoC students, who:
- Can type fast and prefer typing
- Are reasonably comfortable with command-line inputs
- Wish to label contacts by category (e.g. professors, classmates from certain courses, friends)
- Have many different ways to reach their contacts (e.g. social media like Telegram/Discord, additional phone numbers like house phone)
Value proposition: Manage contacts quickly via text commands, with useful features relevant to SoC students.
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
user | add contacts | keep track of my friends and schoolmates |
* * * |
user | delete contacts | remove my contact with that person |
* * * |
user | view my contacts | know who I have as contacts |
* * |
user | edit contacts | make changes to my contact info when they occur |
* * |
user | search for contacts | find a specific contact directly and easily |
* * |
user | add tags to contacts | classify them based on contact type |
* * |
user | merge duplicate contacts | my contact list stays clean |
* * |
user | sort contacts by certain criteria | find contacts satisfying a certain criteria easily |
* * |
user | save alternate contact info for my contacts | keep track of the various ways I can contact the same person |
* * |
user | pin frequent contacts so they appear at the top when I open the app | access my most important contacts quickly |
* * |
user | indicate where I met each contact | keep track of people I have various levels of familiarity with |
* * |
user | view contacts by groups or type | more easily manage related contacts |
* * |
user | export my contacts to an external file | backup my contacts’ information |
* * |
user | import my contacts from an external file | quickly populate the app with my existing contacts |
* * |
user | clear all contacts data | quickly erase all information stored when I will no longer use the app |
* |
user who prefers CLI | use keyboard shortcuts | perform tasks more efficiently |
* |
user | see a different background colour for each contact | differentiate between contacts more easily |
* |
infrequent user | view a “cheatsheet” or help dialog for the text commands | remember some basic commands I may have forgotten |
* |
advanced user | search/filter by specific parts of contacts (e.g. containing certain words) | narrow down contacts to exactly what I am looking for |
* |
user who prefers CLI | switch between previously entered commands in history | easily repeat previous commands |
* |
busy user | use icons to denote certain contact information | identify the information I want at a glance |
Use cases
(For all use cases below, the System is the ConText
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Add a contact
MSS
- User requests to add a contact.
-
ConText adds the contact.
Use case ends.
Extensions
-
1a. The given data is invalid.
-
1a1. ConText shows an error message.
Use case resumes at step 1.
-
Use case: UC02 - Delete a contact
MSS
- User requests to view the list of contacts (UC03).
- User requests to delete a specific contact in the list.
-
ConText deletes the contact.
Use case ends.
Extensions
-
2a. An invalid contact to edit is specified.
-
2a1. ConText shows an error message.
Use case resumes at step 2.
-
Use case: UC03 - List all contacts
MSS
- User requests to list contacts.
-
ConText shows a list of contacts.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends
Use case: UC04 - Edit a contact
MSS
- User requests to view the list of contacts (UC03).
- User requests to edit a contact.
-
ConText edits the contact.
Use case ends.
Extensions
-
2a. An invalid contact to edit is specified.
-
2a1. ConText shows an error message.
Use case resumes at step 2.
-
-
2b. The given data is incorrect.
-
2b1. ConText shows an error message.
Use case resumes at step 2.
-
Use case: UC05 - Clear all contacts
MSS
- User requests to clear all contacts.
-
ConText clears all contacts.
Use case ends.
Use case: UC06 - Find a contact
MSS
- User requests to find a contact.
-
ConText displays a list of contacts matching the given data.
Use case ends.
Extensions
-
2a. The filtered list is empty.
Use case ends.
Use case: UC07 - Filter tags
MSS
- User requests to filter the list of contacts by a given tag.
-
ConText displays a filtered list of contacts based on the given tag.
Use case ends.
Extensions
-
2a. The filtered list is empty.
Use case ends.
Non-functional requirements
- “Brownfield” - Changes to the codebase must be done in small increments.
- “Typing preferred” - The product must target users who can type fast and prefer CLI as their means of input.
- “Single user” - The product must be designed for a single user.
- “Incremental” - The product must be developed breadth-first as well as consistently each week.
- “Human editable file” - Data must be stored locally in a human-editable text file format.
- “No DBMS” - DataBase Management Systems must not be used.
- “OO” - Software must mostly follow the object-oriented paradigm.
- “Platform independent” - Software must work on Windows, Linux, and OSX. I.e., avoid OS-dependent libraries and OS-specific features.
- “Java version” - Software must work on a computer that has Java version 11 installed.
- “Portable” - Software must work without requiring an installer.
- “No remote server” - Software must not depend on a remote server.
- “External software” - Any 3rd party frameworks/libraries/services used must:
- Be free and open-source (except services), with permissive license terms (e.g. non-time limited trial).
- Not require installation by users. Services that require account creation on their 3rd party service are strongly discouraged.
- Not violate other project constraints.
- Be approved by the teaching team.
- “Screen resolution” - GUI must work well for standard screen resolutions and scales, as specified in the admin info. GUI must still be usable if those factors are non-standard.
- “Single file” - Software must all be packed into a single JAR file.
- “File size” - Software must not exceed 100MB and must not be unnecessarily bloated. Documents must not exceed 15MB per file.
- “PDF-friendly” - Developer and user guides must be PDF-friendly, without using expandable panels, embedded videos, animated GIFs etc.
- “Minimal network” - Any public APIs used should have a fallback mechanism in the event that they are down. Any NUS data used should have the approval of NUS IT.
- “Testability” - Features should not be hard to test or make the product hard to test, be the testing manual or automated.
- “CLI first” - Users who can type fast should be able to accomplish most tasks faster via the CLI as compared to if they were to use a hypothetical GUI-only version of the product.
- There must exist an image with the exact name and format
docs/images/Ui.png
depicting the final product, with similar proportions as the original AB3 image. - There must exist an
AboutUs
page that closely follows the original template, such that CS2103 grading scripts can understand it.- Each team member must have an appropriately named lowercase PNG of their profile picture, as specified in the admin info.
- There must exist Project Portfolio Pages (PPPs) in
docs/team/
, containing sections specified in the admin info.- Each team member must have their own appropriately named lowercase page file, as specified in the admin info.
- The page must be written to account for paged PDF conversion.
- Documentation must be built using Jekyll or MarkBind, then hosted via GitHub Pages, such that they are compatible with CS2103 grading scripts.
- Branches must not be deleted after their associated PRs have been merged, so that CS2103 grading scripts can detect that the correct workflow was used.
- The
README.md
must acknowledge SE-EDU’s AB3, which this project is based on. It should also contain theUi.png
, as well as the repo’s GitHub Actions build status badge.
Glossary
-
Architecture Diagram: A visual representation that depicts the high-level design and structure of the software application.
-
Component: A modular part of the system with a distinct responsibility. The main components mentioned are UI, Logic, Model, and Storage.
-
Commons: Classes or utilities used by multiple components of the application.
-
UI (User Interface): The space where interactions between humans and the software occur. The goal of this interaction is to allow effective operation and control of the machine from the human end.
-
GUI (Graphical User Interface): A type of user interface that allows users to interact with electronic devices through graphical elements such as images, buttons, icons, and windows instead of text-based command lines.
-
Logic: In the context of software, it refers to the set of rules and algorithms that process and respond to user inputs.
-
Model: The part of the application that manages data and application logic.
-
Storage: The part of the application responsible for saving and loading data to and from persistent storage.
-
API (Application Programming Interface): A set of rules and tools that allows different software applications to communicate with each other. In this context, it refers to the interfaces defined for each component, such as
Logic.java
,Model.java
, etc. -
Sequence Diagram: A type of UML diagram that shows how objects interact in a specific order.
-
UML (Unified Modeling Language): A standardized modeling language enabling developers to specify, visualize, construct, and document artifacts of a software system.
-
PlantUML: A tool that allows users to create UML diagrams using a simple and intuitive language.
-
puml
files: Files written in a text-based markup language used by PlantUML to generate UML diagrams. -
MSS (Main Success Scenario): Represents the sequence of steps that describe a successful execution of a use case.
-
CLI (Command Line Interface): A user interface that allows users to interact with the software by typing text-based commands.
-
JavaFX: A Java library used to create desktop applications. It is used for designing the user interface of this application.
-
ObservableList: A list that allows listeners to track changes when they occur. Used in the context of JavaFX to automatically update the UI when the data changes.
-
JSON (JavaScript Object Notation): A lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate. Used for storing data in this application.
-
JUnit: A testing framework for Java programming language. JUnit5 refers to the fifth major version of this framework.
-
Predicate: A functional interface that represents a condition (test) and is used to filter data.
-
Brownfield: A term used in software development to describe a project that has existing constraints, typically an existing system or codebase, as opposed to a greenfield project which starts from scratch.
-
Platform independent: Software that can run on any computer regardless of its operating system, such as Mac/Windows/Linux.
-
Human editable file: A file format designed to be easily readable and editable by humans.
-
Portable: Software that doesn’t require installation and can be run from any location, such as from a USB stick.
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.

Launch and shutdown
-
Initial launch
-
Download the jar file and place it into an empty folder
-
Open a command terminal,
cd
into the folder you put the JAR file in, and use thejava -jar context.jar
command to run the app.
-
Adding a new contact
-
Adding a contact with all fields
-
Test case:
add n/John Doe p/12345678 e/john@example.com o/notes t/friend a/Telegram: johndoe
Expected: A new contact with the name “John Doe”, phone number “12345678”, email “john@example.com”, a note “notes”, tagged as “friend”, and an alternate contact “Telegram: johndoe” is added to the list. -
Test case:
add n/Alice p/87654321 e/alice@example.com
Expected: A new contact with the name “Alice”, phone number “87654321”, and email “alice@example.com” is added. Optional fields are left blank. -
Other incorrect add commands to try:
add
,add n/John Doe
,add e/john@example.com
,add n/John Doe p/12
Expected: Error message indicating the correct format for theadd
command.
-
Editing an existing contact
-
Editing a contact’s name and email
-
Prerequisites: Have at least one contact in the list.
-
Test case:
edit 1 n/Jane Doe e/jane@example.com
Expected: The first contact in the list has its name changed to “Jane Doe” and email to “jane@example.com”. -
Test case:
edit 1 t/
Expected: All of the existing tags of the first contact in the list are removed while other information of the contact remains unchanged. -
Test case:
edit 2 n/Bob
Expected: Error message indicating the correct format for theedit
command. -
Other incorrect edit commands to try:
edit
,edit x
(where x is larger than the number of contacts in ConText),edit 1 n/
,edit 1 e/
Expected: Error message indicating the correct or valid usage of theedit
command.
-
Deleting a contact
-
Deleting a contact while all contacts are being shown
-
Prerequisites: List all contacts using the
list
command. 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. -
Test case:
delete 1 2 3
Expected: First, second, and third contacts are deleted from the list. Details of the deleted contacts shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 1 1 2
Expected: First and second contacts are deleted from the list without duplication. Details of the deleted contacts shown in the status message. Timestamp in the status bar is updated. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Filtering contacts by tag
-
Filtering contacts using a specific tag
-
Test case:
filter friend
Expected: List all contacts tagged as “friend”. -
Other incorrect filter commands to try:
filter
,filter @#$%
(assuming no such tags)
Expected: Error message indicating the correct usage of thefilter
command or no contacts found message.
-
Saving data
-
Dealing with missing/corrupted data files
-
Test case: Navigate to the folder with the JAR file, and remove all files and subfolders except the JAR file. Relaunch the app. Expected: The app will launch normally, with sample contact data.
-
Test case: Navigate to the folder with the JAR file, and make arbitrary changes to the
\data\contacts.json
file, so as to render it invalid. Relaunch the app. Expected: The app will launch normally, with an empty contact list.
-
Appendix: Planned enhancements
-
Currently, error messages displayed in ConText are generic. For example, if a user enters a negative index, the error message
Invalid command format
is displayed, even if the command format is technically correct. We plan to add more specific error messages for invalid indices (e.g. non-positive, too large, or does not exist in the list), to let the user know that the index itself is invalid, and why. -
Currently, special characters such as
-
and/
are not allowed in names, even though they could conceivably be part of a contact’s legal name. We plan to allow for special characters to be included in a contact’s name. -
Currently, the
find
command only allows for matching of full words. For example, the input keywordJohn
will not match the nameJohnny
stored in the list. This may lead to unintended behaviour for some users. We plan to allow partial matches of contact names forfind
. -
Currently, duplicate contacts are only detected by contacts having completely identical names, and not by other fields such as email address. Although this is meant to remove ambiguity in duplicate detection, it may be counter-intuitive for some users. We plan to include additional warning messages for the detection of duplicate contacts. We will warn users if they are adding contacts with duplicate information, such as duplicate email address, or names which differ only by whitespace (in the middle). The user can then confirm whether they would like the duplicate contact to go through, or whether they would like to make changes to the duplicate contact.
-
Currently, duplicate values for deletion indices, as well as parameters like
t/
anda/
, get silently merged. This is not outright rejected for the convenience of users. However, users may have accidentally entered such duplicate values, which may result in the app’s behaviour differing from users’ expectations. In such cases, we plan to display additional warning messages for commands likeadd
,edit
, anddelete
, so that users may check if their specifying of duplicate values is intentional. Users may then press enter again to confirm the command’s execution, or edit the command. -
Currently, if no note (i.e. no
o/
parameter) is specified when adding a contact, the note’s value defaults to being empty (""
). The UI accounts for empty notes by not taking up an extra line to display the empty note. When users do specify a note, they may explicitly specify an empty note (i.e.o/
with no value). This is not outright rejected for the convenience of users, since empty notes are allowed. However, users may have forgotten to specify a value for the note, which may result in the app’s behaviour differing from users’ expectations. In such cases, we plan to display an additional warning message for commands likeadd
, so that users may check if their specifying of empty notes is intentional. -
Currently, users are allowed to enter very flexible phone number values. The only validation requirement is that the phone number begins with 3 digits. This allows users to use the feature as they wish. For example, although the standard intended usage is for users to enter just the digits of a phone number (e.g.
98765432
), they are also allowed to enter a value such as65432109 (office); 98765432 (mobile)
. However, this flexibility may result in users accidentally entering invalid phone numbers, such as9876p/5432
. Therefore, if users enter a phone number that does not contain only 3-15 digits, we plan to display an additional warning message for commands likeadd
andedit
, so that users may check if their specifying of such a value is intentional. Users may then press enter again to confirm the command’s execution, or edit the command. The added need to confirm non-standard phone numbers nudges users towards using the alternate contacts feature for additional phone numbers instead. -
Currently, alternate contacts do not allow spaces in the “type” portion, and do not allow special characters such as
@
in the “username” portion. We plan to allow spaces in the “type” portion for added flexibility. We also plan to allow special characters in the “username” portion, by allowing username values which match existing phone number/email validation. Similarly, we would also allow all phone numbers to optionally start with the special character+
before the required digits.