Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Appendix: Future
Acknowledgements
- The feature to filter file format for the Upload Command was adapted from this StackOverflow post.
- Github Copilot / ChatGPT 4.0 was used to autocomplete parts of code
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml files used to create diagrams are in this document 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
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, StatusBarFooter, PersonDetailedView 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:

The sequence diagram below illustrates the interactions within the Logic component, taking execute("delete 1") API call as an example.

DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the Logic component works:
- When
Logicis called upon to execute a command, it is passed to anAddressBookParserobject which in turn creates a parser that matches the command (e.g.,DeleteCommandParser) and uses it to parse the command. - This results in a
Commandobject (more precisely, an object of one of its subclasses e.g.,DeleteCommand) which is executed by theLogicManager. - The command can communicate with the
Modelwhen it is executed (e.g. to delete a client).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and theModel) to achieve. - If the command is one that triggers a
ConfirmationHandler, e.g. delete, clear, add (duplicate), theConfirmationHandlerobject will handle whether the user confirms or cancels the action. - The result of the command execution is encapsulated as a
CommandResultobject 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
AddressBookParserclass 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 theAddressBookParserreturns 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). - 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)
Tag list in the AddressBook, which Person references. This allows AddressBook to only require one Tag object per unique tag, instead of each Person needing their own Tag objects.
Storage component
API : Storage.java

The Storage component,
- can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
- inherits from both
AddressBookStorageandUserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Modelcomponent (because theStoragecomponent’s job is to save/retrieve objects that belong to theModel)
Common classes
Classes used by multiple components are in the seedu.address.commons package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Upload Command
Implementation
The upload mechanism is facilitated by JFileChooser by the Java Swing toolkit. It extends Command and allows users to upload PNG images via saving
the file path of the picture.
Step 1: The user types upload INDEX which creates an UploadCommand after passing through UploadCommandParser.
Step 2: If the user is on Windows, a JFileChooser dialog opens for the user to select files, with a FileFilter
for PNG files only. Else, the user will be notified that it is not supported for Mac/Linux.
Step 3: If a valid PNG file is chosen, the File path is recorded as a new ProfilePicFilePath. A new client is created
with the updated path. Else, it will throw an error message notifying of invalid file type.
An activity diagram for this feature is as follows:

Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- Financial advisors who frequently or specialise primarily in client outreach
- 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
- Keep track of who has and has not been contacted recently
- Sort clients based on various categories
- Filter for clients by above categories
User stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* |
Forgetful Financial Advisor | Have a quick view of the contacts I need to contact | Keep track of them without using my own memory |
** |
Earnest Financial Advisor | Tag clients with their net worth range | Categorise clients based on their financial standing to tailor advice |
** |
Connected Financial Advisor | Highlight upcoming client birthdays | Be reminded to send birthday wishes and foster client relationships |
*** |
Organised Financial Advisor | Mark a client as paid with a specified policy renewal feature | Easily keep track of which clients have paid their premiums and when their renewal is due |
** |
|||
** |
Financial Advisor with many clients | Keep a template of catch-up messages to send to clients | Efficiently send messages to clients when necessary |
* |
|||
** |
|||
*** |
Financial Advisor who just met someone new | Add contacts | Have the contact in my list |
*** |
Retiring Financial Advisor | Delete contacts | Get rid of contacts that are no longer useful |
* |
|||
** |
Meticulous Financial Advisor | Edit contact details | Update when their details as necessary |
*** |
Meticulous Financial Advisor | Assign tags to my contacts | Easily sort my contacts by certain tags |
** |
Financial Advisor who woke up with someone in mind | Filter my contacts based on attributes | Find that one contact quickly |
* |
|||
** |
|||
* |
Financial Advisor who just downloaded the app | See sample data | See how a populated version of the app will look like |
* |
|||
** |
Financial Advisor who is being chased by his boss | Add reminders on when clients’ contracts need to be renewed | Ensure clients are always up to date on their contracts |
* |
Financial Advisor who just downloaded the app | Delete sample/dummy data | Start using the app in a fresh state |
* |
Financial Advisor with many clients | Add profile pictures to my clients | Recognize my clients when I meet them in person |
* |
|||
*** |
Lost Financial Advisor | See a help page of all commands | Refer back to the page anytime I forget the instructions |
*** |
Forgetful Financial Advisor | See all my contacts | View my entire contact list |
{More to be added}
Use cases
(For all use cases below, the System is F.A.R.T and the Actor is the user, unless specified otherwise)
Use case 1: Add a contact
MSS
- User requests to add a new contact.
-
F.A.R.T adds new contact and shows a confirmation message.
Use case ends.
Extensions
-
1a. F.A.R.T detects an error in the provided details.
-
1a1. F.A.R.T shows an error message.
Use case ends.
-
-
1b. F.A.R.T detects the existence of a duplicate contact.
-
1b1. Prompt window appears (UC 6).
Use case ends.
-
Use case 2: Find a contact
MSS
- User requests to find a contact.
-
F.A.R.T shows a list of related contacts.
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
- 1b. No parameters are given.
- 1b1. F.A.R.T shows an error message
Use case ends.
- 1b1. F.A.R.T shows an error message
- 1c. Parameters are given but keywords are empty.
- 1c1. F.A.R.T does not execute command and waits for more input by user.
Use case ends.
- 1c1. F.A.R.T does not execute command and waits for more input by user.
Use case 3: Mark a contact as paid or unpaid
MSS
- User requests to mark or unmark a contact.
-
F.A.R.T marks or unmarks contact and shows a confirmation message.
Use case ends.
Extensions
-
1a. The given index is invalid.
-
1a1. F.A.R.T shows an error message.
Use case ends.
-
Use case 4: Delete a contact
MSS
- User requests to delete a contact.
- F.A.R.T requests confirmation.
- User confirms.
-
F.A.R.T deletes the contact and shows a confirmation message.
Use case ends.
Extensions
-
1a. The given index is invalid.
-
1a1. F.A.R.T shows an error message.
Use case ends.
-
-
2a. User declines.
-
2a1. F.A.R.T shows a confirmation message.
Use case ends.
-
Use case 5: Edit a contact
MSS
- User requests to edit a contact.
- F.A.R.T edits contact and shows a confirmation message.
Use case ends.
Extensions
-
1a. The given index is invalid.
-
1a1. F.A.R.T shows an error message.
Use case ends.
-
-
2a. No prefix given or wrong prefix given
-
2a1. F.A.R.T shows an error message
Use case ends.
-
Use case 6: Prompt Window
MSS
- F.A.R.T prompts the user to confirm their action.
- User confirms.
- F.A.R.T carries out the command and displays a confirmation message.
Use case ends.
Extensions
- 2a. The user declines.
-
2a1. F.A.R.T displays a confirmation message.
Use case ends.
-
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
17or above installed. - Should work without the usage of an external database.
- Should work without any connection to a remote server or use of any cloud computing service.
- A user with above 60WPM typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks in under 10 seconds
- The system should be able to handle storage of over 1000 contacts and still execute queries within 1 second for typical usage.
- The product is not required to have its own messaging service.
- Queries to the system (find, list, paid etc.) should be responded to within 3 seconds.
- The product should not use any images / comments / jokes deemed offensive to Financial Advisors.
- The system should be usable by a novice with basic command-line knowledge.
- Any lists or iterables should be 1-indexed assuming the user does not have programming experience.
- The product is catered for use by a single user and interaction between users is not supported.
- Data collected should be stored locally, and be human editable.
- The product should be packaged in a single
jarfile without the need for other installers. - The GUI should be optimised for standard screen resolutions 1920x1080 and higher, and screen scales 100% and 125%.
- The size of the product should not exceed 100mb.
- Visuals and text should be a large enough size for clarity.
Glossary
- Mainstream OS: Windows, Linux, Unix, macOS
- Private contact detail: A contact detail that is not meant to be shared with others
- Financial Advisor: A professional who provides expertise for clients’ decisions around money matters, personal finances, and investments
- Client: A financial advisor’s contact
- GUI: Graphical User Interface, a type of user interface through which users interact with electronic devices via visual indicator representations
- Paid: A client has the status paid when they have paid for their current policy and the current policy is active
- Unpaid: A client has the status unpaid when they have not paid for their current policy and the current policy is expired
- Payment frequency: The frequency of which a Financial Advisor receives payments from their clients. Typically, every 1, 3, 6 or 12 months
- Policy: An agreement between the Financial Advisor and their client on the financial advisory services provided
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
-
Run the jar file via terminal.
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 running the jar file via terminal.
Expected: The most recent window size and location is retained.
-
Adding a client
- Adding a client while all clients are being shown
- Test case:
add n/John Cena p/98765432 e/johncena@gmail.com b/10 01 1990
Expected: A new client is added to the list. The new client is shown in the list. - Test case:
add
Expected: No client is added. Error details shown in status message. - Test case:
add n/John Cena p/12345678 e/johncena@gmail.com b/10 01 1990
Expected: No client is added. Error details shown in status message. - Test case:
add n/John Cena p/98765432 e/johncena@gmail.com
Expected: No client is added. Error details shown in status message. - Test case:
add n/John Cena p/98765432 b/10 01 1990
Expected: No client is added. Error details shown in status message. - Test case:
add n/John Cena e/johncena@gmail.com b/10 01 1990
Expected: No client is added. Error details shown in status message. - Test case:
add p/98765432 e/johncena@gmail.com b/10 01 1990
Expected: No client is added. Error details shown in status message.
- Test case:
Clearing all clients
-
Clearing all clients while all clients are being shown
- Test case:
clear
Expected: UI box is shown to confirm that user wants to clear all contacts from F.A.R.T. If user clicks yes, all contacts are removed from the list, otherwise it will cancel the operation.
- Test case:
Opening help window
-
Opening help window while all clients are being shown
- Test case:
help
Expected: A new window UI is opened showing the help page. - Test case:
help me please
Expected: A new window UI is opened showing the help page. - Test case:
hElP
Expected: No window is opened. Error details shown in the status message.
- Test case:
Listing all clients
- Listing all clients while all clients are being shown
- Test case:
list
Expected: All clients are shown in the list. - Test case:
list none
Expected: All clients are shown in the list. - Test case:
lIsT
Expected: If list is already shown, stays listed, else list will not appear. Error details shown in the status message.
- Test case:
Deleting a client
-
Deleting a client while all clients are being shown
-
Prerequisites: List all clients using the
listcommand. Multiple clients 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. -
Test case:
delete 0
Expected: No client is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
delete,delete x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Finding a client
-
Finding a client while all clients are being shown
-
Prerequisites: List all clients using the
listcommand. Multiple clients in the list. -
Test case:
find n/John
Expected: Clients with name containingJohnare shown in the list. -
Test case:
find a/Serangoon
Expected: Clients with addresses containingSerangoonare shown in the list. -
Test case:
find
Expected: No client is found. Error details shown in the status message. -
Test case:
find
Expected: No output is given. Program waits for more user input.
-
Editing a client
-
Editing a client while all clients are being shown
-
Prerequisites: List all clients using the
listcommand. Multiple clients in the list. - Test case:
edit 1 n/John Doe
Expected: First contact’s name is changed toJohn Doe. Details of the edited contact shown in the status message. UI updates to the corrected name. - Test case:
edit 0 n/John Doe
Expected: No client is edited. Error details shown in the status message. - Test case:
edit 1 n/Donald Trump p/96253647
Expected: First contact’s name is changed toDonald Trumpand phone number is changed to96253647. Details of the edited contact shown in the status message. UI updates to the corrected name and phone number. - Other incorrect edit commands to try:
edit,edit x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Marking a client as paid
-
Marking a client as paid while all clients are being shown
-
Prerequisites: List all clients using the
listcommand. At least one client in the list. - Test case:
paid 1 f/1
Expected: First contact is marked as paid. Details of the marked contact shown in the status message. - Test case:
paid 0
Expected: No client is marked as paid. Error details shown in the status message. - Test case:
paid 1 f/0
Expected: No client is marked as paid. Error details shown in the status message. - Test case:
paid 1 f/100
Expected: No client is marked as paid. Error details shown in the status message. - Test case:
paid
Expected: No client is marked as paid. Error details shown in the status message.
-
Marking a client as unpaid
-
Marking a client as unpaid while all clients are being shown
- Prerequisites: List all clients using the
listcommand. At least one client in the list. - Test case:
unpaid 1
Expected: First contact is marked as unpaid. Details of the marked contact shown in the status message. - Test case:
unpaid
Expected: No client is marked as unpaid. Error details shown in the status message.
- Prerequisites: List all clients using the
Exiting the app
-
Exiting the app while all clients are being shown
- Test case:
exit
Expected: App window closes.
- Test case:
Saving data
-
Dealing with missing data files
- To simulate missing file delete addressbook.json file located at data/addressbook.json before launching the app.
- Launch the app
- The app should launch without any issues and show a list of sample contacts.
- Perform any command to create a new addressbook.json
-
Dealing with corrupted data files
- To simulate corrupted file, edit addressbook.json file located at data/addressbook.json and add some random text.
- Launch the app
- The app should launch without any contacts displayed.
- Close the app and delete addressbook.json file located at data/addressbook.json.
- Launch the app
- The app should launch without any issues and show a list of sample contacts.
- Perform any command to create a new addressbook.json
Appendix: Future
Future Enhancements
Team size: 5
- Ensure all panels such as command panel are shown even in minimum resolution window.
- Automatically update the client’s detailed view page whenever a change is made to their details.
- Allow for more flexible policy start dates as we currently assume all policies start on the 1st of the respective months.
- Allow users to input their own template messages and update template message labels accordingly.
- Allow for more flexibility regarding policy frequency, as now it is fixed at 1, 3, 6 or 12 months.
- Enhance specificity for finding by birthday (find by month, day, year) as current implementation will match against the whole string representation of birthday.
- Enhance clarity of error messages for phone numbers (define what is Singapore numbers in the application itself).
- Rewording of error messages to provide greater clarity on what is done wrongly, especially for parameters in
AddandEditcommands. - Resizing of help window for better visibility
- Inclusion of hotkeys to open
PersonDetailedViewwindow and toggling between list selection and command input.