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
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
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
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object residing in theModel
.
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
Logic
is called upon to execute a command, it is passed to anAddressBookParser
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 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), theConfirmationHandler
object will handle whether the user confirms or cancels the action. - 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
AddressBookParser
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 theAddressBookParser
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 address book data i.e., all
Person
objects (which are contained in aUniquePersonList
object). - stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
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
AddressBookStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.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
17
or 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
jar
file 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
list
command. 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
list
command. Multiple clients in the list. -
Test case:
find n/John
Expected: Clients with name containingJohn
are shown in the list. -
Test case:
find a/Serangoon
Expected: Clients with addresses containingSerangoon
are 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
list
command. 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 Trump
and 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
list
command. 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
list
command. 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
Add
andEdit
commands. - Resizing of help window for better visibility
- Inclusion of hotkeys to open
PersonDetailedView
window and toggling between list selection and command input.