This project is based on the AddressBook-Level3 project created by the SE-EDU initiative.
Application icon was taken from Flaticon
Refer to the guide Setting up and getting started.
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.
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),
interface
with the same name as the Component.{Component Name}Manager
class (which follows the corresponding API interface
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.
The API of this component is specified in Ui.java
In the class diagram above, it is showing the state where the Finance
tab is selected.
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, ContactsTab
, FinanceTab
, EventsTab
, 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.
Depending on the Tab currently selected by the user, the MainWindow
will display the corresponding PersonListPanel
, FinanceListPanel
or EventListPanel
.
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,
Logic
component.Model
data so that the UI can be updated with the modified data.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Person
object residing in the Model
.In the future, we aim to be able to abstract out the Card, ListPanel, and Tab (UI) accordingly, to make adding tabs much easier and convenient.
API : Logic.java
Here's a (partial) class diagram of the Logic
component within a Tab:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("delete 1")
API call as an example.
Note: This takes place within the ContactsTab.
Note: The lifeline for DeleteContactCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the Logic
component works:
Logic
objects. These Logic
objects share the same Model
and Storage
, but have different Parsers
Logic
is called upon to execute a command, it is passed to that Tab's Parser
(e.g. in our class diagram above the ContactParser
receives the command).DeleteContactCommandParser
) and uses it to parse the command.Command
object (more precisely, an object of one of its subclasses e.g., DeleteContactCommand
) which is executed by the LogicManager
.Model
when it is executed (e.g. to delete a contact).CommandResult
object which is returned back from Logic
.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:
ContactParser
, FinanceParser
, EventParser
) class creates an XYZCommandParser
(XYZ
is a placeholder for the specific command name e.g., AddEventCommandParser
) which uses the other classes shown above to parse the user command and create a XYZCommand
object (e.g., AddContactCommand
) which the ContactParser
returns back as a Command
object.
DateTimeParser
is included here to show all Parser Classes. However, only a few Command Parsers interact with the DateTimeParser
(when date-time inputs are involved).XYZCommandParser
classes (e.g., AddContactCommandParser
, DeleteFinanceCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model
component,
Person
objects (which are contained in a UniquePersonList
object).ObservableList<Person>
where Person
objects 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. This is the same for Event
and Finance
.UserPref
object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref
objects.Model
represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below.
For AddressBook:
For EventsBook: note that multiple Person
objects are can be associated to an Event as clients
For FinanceBook:
API : Storage.java
The Storage
component,
AddressBookStorage
, EventsBookStorage
, FinanceBookStorage
and UserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve objects that belong to the Model
)EventsBook
and FinanceBook
might contain Persons from the AddressBook
(only upon creation)Classes used by multiple components are in the seedu.addressbook.commons
package.
This section describes some noteworthy details on how certain features are implemented.
In FreelanceBuddy, the creation of Finance entries (commissions and expenses) includes validation for clients. In the case that the user attempts to create a Finance entry with an associated client, FreelanceBuddy will check if the client exists in the Contacts Tab and only create the entry if it does.
Both Commission
and Expense
classes have the same attributes as Finance
(as a result of inheritance), while both AddCommissionCommand
and AddExpenseCommand
classes handle the validation in similar ways. Hence, for simplicity, we will only discuss how a Commission
is added to the Model
, as the implementation is similar for Expense.
Given below is an example usage scenario and how the command behaves at each step.
Step 1. We assume that a client named John
already exists in the Contacts Tab. The user attempts to create a new Commission from John Doe
, with the amount 20
and the description Chatbot
.
He enters the command add-c c/John a/20 d/Chatbot
in the Finance Tab. The LogicManager
passes this to the FinanceParser
, which identifies it as a command to add a commission. Then it creates a AddCommissionCommandParser
and calls the AddCommissionCommandParser#parse()
method.
Step 2. The AddCommissionCommandParser
parses the given command into an AddCommissionCommand
with a Commission
that contains the following attributes: Amount
containing 20
, Description
containing Chatbot
, TimeDue
containing the time of creation (by default), and most notably, a dummy Person
object containing placeholder values for all its attributes other than the name which is John Doe
.
This dummy Person
object is important as it allows us to fetch the actual Person
object from the Model
later on.
Note: Only the instantiation of the dummy Person
object is included in the diagram.
Step 3. The LogicManager
then calls AddCommissionCommand#execute()
. If the client exists (this is always the case for Commission
), it will call the Model#isValidClient()
method to check if the client exists in Model
. If it does not, a CommandException
will be thrown.
Step 4. Having verified that the client exists in Model
, AddCommissionCommand
then calls the Model#getMatchedClient()
method to fetch the actual Client
object in Model
. This Client
field in the Commission
is then set to this actual Client
.
Step 5. Lastly, the Commission
in AddCommissionCommand
is added to the Model
, while returning a CommandResult
with the details of the Commission
formatted into a result String
. This result String
is then printed in the status box.
In FreelanceBuddy, we have multiple commands that make use of a Predicate
to filter the lists.
(e.g. filter-c
, filter-t
, summary
...)
In this example, we will use the summary
command from the finance tab to demonstrate how FreelanceBuddy
uses a Predicate
to update a FilteredList
in the Model
.
Given below is an example usage scenario and how the command behaves at each step.
Step 1. We assume that the finance tab is already populated with finances from multiple clients. The user now wants to
generate a summary report for the client John Doe
. He enters the command summary John Doe
into the command line.
Step 2. A ClientNameExactMatchPredicate
is created with the argument "John Doe"
. This predicate will be used to
filter the financeList
later on.
Note: The activation bar of the LogicManager continues to the next diagram.
Step 3. SummaryCommand
is then executed by the LogicManager
. The model updates the financeList
with the given
namePredicate
(i.e. ClientNameExactMatchPredicate("John Doe")
). The filteredFinances
list is then fetched from the model.
Step 4. With the filteredFinances
, we then call the static FinanceSummary#generateSummary
method to create a summary
report. The method returns the summary as a string which is then passed as an argument into the CommandResult
constructor.
Note: The activation bar of the LogicManager continues from the previous diagram.
Step 5. The summary report is then displayed in the status box. The list of finances displayed in the finance tab will also update to only show finances related to the given client.
Use of the tab
command to switch between tabs in the UI.
Currently, the application uses the existing TabPane from JavaFX, and it makes use of the tab index to switch tabs.
The commons.core.Tab
object stores both the index and tab name. It also contains the standard index and tab name constants of each tab which can be used by other classes.
You will need to update these constants in commons.core.Tab
if you wish to add/edit/delete a tab from the application.
To create the Tab
object, you need to use the Tab#fromParameter("tabName")
as the constructor is private.
Note that the Tab
object will convert and store the index based on the given tab name(assuming it is valid).
Note that ui.ContactsTab
, ui.EventsTab
and ui.FinanceTab
does not implement from core.tab.Tab
as they have different purposes.
Given below is an example usage scenario and how the tab mechanism behaves at each step.
Step 1. The user launches the application, and is on the contacts tab.
Step 2. The user executes tab events
command to switch from the contacts tab to the events tab.
The TabCommandParser
creates the Tab
object using the ParserUtil#parseTab("events")
method.
Step 3. The method checks if it is a valid input using Tab#isValidParameter("events")
before creating the Tab
object.
Step 4. The Tab
object converts the given parameter into the appropriate tab index, and stores both the parameter and index within the object.
The Tab
object is passed from the TabCommandParser
to the TabCommand
,
which returns the tab index from the Tab
object using Tab#getZeroBasedTabIndex()
.
In this case, the return value is 2 since the index for the Events Tab is 2.
Step 5. The ContactsTab
switches tab in the GUI using the ContactsTab#handleTabChange(2)
The following sequence diagram represents the user is changing from the Contacts tab to the Events tab as mentioned above.
The following activity diagram summarise what happens when a user changes a tab.
Other than the basic understanding of how the Date-time inputs are determined, the rules and assumptions it has. Read here for more info: Accepted Date-time Formats. It would be important to understand the inner-workings of the date-time parser to appreciate certain design choices made when implementing features.
The choice to implement a more advanced date-time parser than what is available in the Java LocalDateTime
library or other external libraries is:
DateTimeFormatter
FormatsFirst, we start off by accepting more formats of Date
and Time
that Java's LocalDateTime
library provides (Numbered Date-time formats). All summarised in the User Guide.
Parsing for this is done by "brute force" handled by the number of elements the date-time format has (the reason it is done this way will be explained in a later section):
To illustrate how parsing of multiple formats is done, the sequence diagram shows parseTwoElementsNumberTimeFormat()
, one of the methods that parses multiple formats, and how it matches the input with a format and parses it:
In words:
DateTimeParser
will call the relevant private static
method to parse the respective input (in this case parseTwoElementsNumberTimeFormat()
)LocalTime
, the program will loop through each format. (h a
, h:mm a
and h.mm a
)DateTimeFormatter
is built to be case-insensitive, with the format at that point of execution and to language English (relevant to formats that have letters).LocalTime.parse()
is called with the DateTimeFormatter
and the program attempts to parse the input with the specified format.LocalTime
instance is returned.null
to indicate a failed parse.This method is repeated with the other Numbered Time and Numbered Date formats.
Of note as well, is the formats that do not contain year inputs e.g.
d/M
,d MMM
, etc. In these cases, the year will be set to the current year that the method is called. This is done with building theDateTimeFormatter
with the year using methodparseDefaulting(ChronoField.YEAR, getToday().getYear())
With this, this will enable date-time inputs to be faster and more convenient as users have a wide variety of formats to choose from.
Another feature we wanted to achieve is for users to use natural language formats that maybe not be as easily expressed in a date or a time. Formats that are usually used when conversing. As there are a lot of possibilities it is impossible to accept all forms, we had to sieve out several more important formats that Freelancers may use more often.
Common references of time: noon, midnight, in _ minutes.
Common references of dates: tomorrow, next week, next Monday, in _ weeks.
Common references that imply both date and time: now, _ from now.
These make sense as scheduling meetings with a client may sound like: "Let's follow-up next week, 4:30pm?"
Similarly, we can achieve this by parsing these inputs based on the number of words it has. For natural language formats as you can see from the User Guide, has formats that correspond to the number of words (For example, 3 word date formats are in the formt of "in _ days/months/years"). Hence, we parsed these inputs using switch cases.
To explain, we have described the implementation of one of methods that parse english date time formats, parseThreeElementsEnglishDateFormat()
in the activity diagram below:
Now we have built the base of how to parse Date, Time and Date Time inputs (both Numbered and Natural Language formats) by their elements. We need a master method to pull all these together. Given a string, how does the program choose the right kind of methods to parse the input?
The parseDateTimeInstance()
method brings together all of this to parse any given string.
To demonstrate how a string is parsed into a LocalDateTime
value given that it can be any combination of Date
, Time
or DateTime
formats. We use the below activity diagram to demonstrate:
To further explain what happens within a "Parse X Inputs" we take a look at one of the implementations, parseThreeElements
.
As you can see this is how given the number of words of input, date-time can be parsed even if input can be a date, time or date-time.
On a higher level, a general flow will look something like this: (note that this is greatly simplified)
In one the above diagram where we talked about parseThreeElements()
we got a glimpse of how the parser parses date-time inputs smartly.
In the event either the date or time is not specified, the parser will assume with a "future-bias" prediction on the unspecified date or time.
For example, when time is not specified, it will be set to the 00:00, signifying the start of the day. Likewise, if the date is not specified, the next occurrence of the date with the specified time will be chosen.
Parsing Durations
This is further shown when parsing durations using parseDateTimeDuration()
<TIME>
to <TIME>
only durations, date will be set to next occurrence of the end time. (Future-Bias assumptions)<DATE>
to <DATE>
only durations, time will be set from 00:00 for start date and 23:59 for end date. (Assuming whole day durations)<DATE><TIME>
to <TIME>
, time will be assumed to be the same date as the start <DATE>
. (Conventional way of communicating e.g. Next Monday 4-6pm)For more information on the assumptions that the parser makes when there are missing <DATE>
or <TIME>
inputs for either start or end time, you can check out the User guide section for this here.
In this section, we will go through some current Feature Flaws that FreelanceBuddy currently has and our plans to fix it.
Currently, when a user deletes or edits a client in the contacts tab, this change is not reflected in the Finance and Events
tabs. For example, when the client John Doe
is deleted from our contacts tab, Finances and Events that were previously tagged
with the client John Doe
will remain unaffected. The user will have to manually change the entries in the Finance and Events
tab to reflect the necessary changes.
We plan on making the edits and deletes from the contacts tab cascade to the other tabs. This will ensure that changes made in the contacts tab will be reflected in the other two tabs, avoiding any potential confusion.
Currently, we do not perform any client validation checks on data that is being loaded in from the json files. For example, if the user decides to edit a Finance entry from the json files, they will be able to change the tagged client to a client that does not exist in their contacts.
We plan on adding an extra layer of client validation checks for when data is being loaded in from the storage. This will help to ensure that the data remains consistent even if the user decides to manually change the json files.
Currently, if user changes the values in the preferences.json
or config.json
files to an illegal value, this will cause
the application to not be able to start. For example, if the user changes the userPrefsFilePath
value in the config.json
file to null
, the application will not be able to start.
We plan on handling this issue by resetting the files to their default values if an invalid input is detected. This will prevent a scenario where the user is unable to launch the app.
Currently, the system allows duplicate contact names due to case sensitivity, which is inconsistent with real-world scenarios where case sensitivity isn't considered.
We plan to implement a case-insensitive check for contact names to prevent duplicate entries. Freelancebuddy will recognize "John" and "john" as the same entry, ensuring uniqueness irrespective of case, preventing the addition of duplicates names based solely on case variation.
Currently, the system allows duplicate contact phone numbers which is inconsistent with real-world scenarios where phone numbers are unique and tied to a single person.
We plan to implement a check for contact phone numbers to prevent duplicate entries, including phone numbers which include country codes
For example, +6598765432
will be considered the same as 98765432
, where +65
is the country code for Singapore.
Currently, the system allows duplicate telegram names which is inconsistent with real-world scenarios where telegram names are unique and tied to a single person.
We plan to implement a check for telegram names to prevent duplicate entries.
Target user profile: Freelancers
Characteristics | What FreelanceBuddy offers |
---|---|
May have multiple concurrent clients and projects | One stop app for managing your contacts, finances and day-to-day events in a easy and structured way |
Good at touch-typing, efficient with keyboard | CLI interface enables quick input and retrieval of your contacts, finances and events without the need of moving your mouse |
Potentially busy and want quick updates | Users can get summary statistics, organise their data and much more all with just one command |
Value proposition: Manage all your freelancing needs in an app that is faster than your typical GUI driven apps.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * | user | switch between the different tabs | view Contacts, Events and Finances in their respective tabs |
* * | user | see an overview of all my tabs | quickly get a look at the important details without needing to navigating into tabs unnecessarily |
* | lazy user | FreelanceBuddy to predict my commands | quickly input commands without typing the entire command |
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | user | add a new client contact | |
* * * | user | delete a client contact | remove entries that I no longer need |
* * * | user | view all my saved clients contact | have an overview of all my clients contacts |
* * * | user | find a client contact by name | locate clients by name without having to go through the entire list |
* * | user | edit a saved client contact | change any details that are wrong or have changed |
* * | experienced user | see statistics of a client | see how much money and time is spent on respective client projects |
* * | user | add favourite clients | see all important clients in the same place |
* | long-term user | see if clients have been worth the time | better choose my clients for the future |
* | long-term user | be able to manage client notes | keep important notes about clients for future references |
* | user | create invoices with client details | save time with manual inputting of client details |
This covers both commission and expense. We will refer to both as C/E.
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | user | add a new C/E | |
* * * | user | delete an old C/E | remove entries that I no longer need |
* * * | user | view all my saved C/E | have an overview of all my C/E |
* * | user | filter by C/E | |
* * | user | edit a saved C/E | change any details that are wrong or have changed |
* * | user with many clients | tag clients to C/E | see which client is involved in a particular C/E |
* * | user with many clients | filter by tagged client | |
* * | user with many clients | get a summary of total C/E by tagged client | know how valuable a client is |
* * | financially savvy user | add time due for C/E | know when to expect cash inflow/outflow |
* * | financially savvy user | filter by a timeframe | know what C/E i received in that given timeframe |
* * | financially savvy user | get a summary of total C/E in a given day/month | get an idea of my financial situation for the time period |
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | user | add a new event | |
* * * | user | delete an old event | remove entries that I no longer need |
* * * | user | view all my saved events | have an overview of all my events sorted by date |
* * * | user | see most urgent events | know what is coming up soon or needs to be done urgently |
* * | user | edit a saved event | change any details that are wrong or have changed |
* * | experienced user | tag clients to events | see which client is involved in a particular event |
* | forgetful user | set recurring reminders for events | be alerted to task that I might forget |
* | user | add location of events | know where this event is taking place |
Precondition: -
MSS
User requests for help.
FreelanceBuddy shows a pop-up with a link to the user guide.
User copies the URL and references the user guide.
Use case ends.
Precondition: User can be on any tab
MSS
FreelanceBuddy shows the current tab user is on.
User requests to switch to another tab (that is not the current one).
FreelanceBuddy switches to the specified tab by the user.
FreelanceBuddy shows the desired tab.
Use case ends.
Extensions
2a. The user inputs an invalid syntax.
2a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
2b. User decides to stay on the current tab.
User case resumes at step 4.
Precondition: User is on Contacts tab
MSS
User requests to add a new contact with details.
FreelanceBuddy creates a new contact and shows it within the list.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Contacts tab, Contacts list must have at least one entry
MSS
User requests to delete specific entry in the list.
FreelanceBuddy deletes the entry.
Use case ends.
Extensions
1a1. FreelanceBuddy shows error message.
Use case resumes at step 1.
Precondition: User is on Contacts tab, Contacts list must have at least one entry
MSS
User requests to view all Contacts.
FreelanceBuddy shows a list of all Contacts.
Use case ends.
Precondition: User is on Contacts tab, Contacts list must have at least one entry
MSS
User requests to find contacts using name keywords.
FreelanceBuddy shows a list of Contacts that contains given name keywords.
Use case ends.
Extensions
1a1. FreelanceBuddy shows 0 contacts.
Use case ends.
Precondition: User is on Contacts tab, Contacts list must have at least one entry
MSS
User requests to find contacts using company keywords.
FreelanceBuddy shows a list of Contacts that contains given company keywords.
Use case ends.
Extensions
1a1. FreelanceBuddy shows 0 contacts.
Use case ends.
Precondition: User is on Contacts tab, Contacts list must have at least one entry
MSS
User requests to edit a contact they see in the contacts tab.
FreelanceBuddy changes the contact fields to the new modified values.
Use case ends.
Extensions
1a1. FreelanceBuddy shows error message.
Use case resumes at step 1.
Precondition: User is on Events tab
MSS
User requests to add a new event.
FreelanceBuddy creates the Event entry and shows it within the list.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
User requests to delete a specific entry in the list.
FreelanceBuddy deletes the entry.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
Use case ends.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
Use case ends.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
User requests to find events using name keywords.
FreelanceBuddy shows a list of Events that contains given name keywords.
Use case ends
Extensions
1a1. FreelanceBuddy shows an empty list.
Use case ends.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
User requests to find events before a specific time.
FreelanceBuddy shows a list of Events that are after now and before the requested time.
Use case ends
Extensions
1a. No Events found that are after now and before the requested time.
1a1. FreelanceBuddy shows an empty list.
Use case ends.
1b. The user inputs an invalid time.
1b1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Events tab, Events list must have at least one entry
MSS
User requests to find events with a specified client.
FreelanceBuddy shows a list of Events which have the client tagged.
Use case ends
Extensions
1a. No Events found that have the client tagged.
1a1. FreelanceBuddy shows an empty list.
Use case ends.
1b. The user inputs a client not registered.
1b1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab
MSS
User requests to add a new finance entry.
FreelanceBuddy adds the new finance entry to the top of the list.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab, Finance list must have at least one entry
MSS
User requests to delete a specific entry in the list.
FreelanceBuddy deletes the entry.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab, Finance list must have at least one entry
MSS
Use case ends.
Precondition: User is on Finance tab
MSS
User requests to filter finance entries by entry type.
FreelanceBuddy shows a list of finance entries of the given type.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab, Finance list must have at least one entry
MSS
User requests to edit a specific entry in the list.
FreelanceBuddy edits the entry.
Use case ends.
Extensions
1a. The user inputs an invalid index.
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
1b. The user inputs an invalid syntax.
1b1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab
MSS
User requests to filter finance entries by client.
FreelanceBuddy shows a list of finance entries tagged to the given client.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab
MSS
User requests to see finance summary for a client.
FreelanceBuddy shows the finance summary for the given client.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Precondition: User is on Finance tab
MSS
User requests to filter finance entries by a timeframe.
FreelanceBuddy shows a list of finance entries for the given timeframe.
Use case ends.
Extensions
1a1. FreelanceBuddy shows an error message.
Use case resumes at step 1.
Aspect | Description |
---|---|
Compatibility | Should work on any mainstream OS as long as it has Java 11 or above installed. |
Performance | 1. Should be able to to hold up to 1000 entires in all tabs without much performance degradation. 2. Should respond to commands within 1s on average for any type of task. |
Usability | 1. User with above average typing speed should be able to accomplish most tasks faster than using mouse and GUIs. 2. CLI commands should be intuitive and easy for the user. 3. Error messages should be informative so users can troubleshoot effectively. 4. Clear and concise documentation available to assist users. |
Reliability | 1. App should be robust and resilient to minimize any crashes or errors. 2. App should have have regular automated backup procedures to ensure data is saved in the case of accidental shut down or crashes to the app. |
This section aims to showcase the effort that we put into FreelanceBuddy as a team. We will highlight the challenges and efforts we faced for each component of FreelanceBuddy.
With FreelanceBuddy, we added the Finance
and Event
entities on to the existing AB3 Person
entity.
These entities and their models were made from scratch, with minimal code reuse from AB3.
With the addition of these entities, we felt that it made the most sense to create two new tabs. This meant that new UI components had to be created for each tab. For this, the main structure of each tab was somewhat similar to the original AB3 UI, however slight adjustments were made to cater to the needs of each tab.
With the creation of three tabs, we realised that separate parsers had to be made. This is because the same command should
have a different result depending on which tab you are on. To achieve this, we made three new parsers - ContactParser
,
FinanceParser
and EventParser
which all extend the ParseCommandHandlers
class. This helped us to manage how commands
were handled in each tab. ContactParser
was adapted from the original AB3 AddressBookParser
while the other two parsers
had very minimal code reuse, due to the fact that they handled very different commands.
For the commands, many of the basic commands (i.e. add, delete and edit) that we added to Finance
and Events
made
use of the existing AB3 commands. Many of the new commands we added (i.e. filter-n
, summary
) relied on the
use of the Predicate
classes. This was adapted from the existing find
command of AB3. While the new commands were not exactly
the same as the find
command, we were able to extract the idea of how to filter a list from the find
command.
We also made an effort to cater to more intuitive user inputs through the implementation of the DateTimeParser
.
We felt that the addition of this DateTimeParser
greatly improved the user experience since many of our commands made
use of both a start and end time. The implementation of this was not trivial and none of the code for this was taken from AB3.
The main challenge we faced with FreelanceBuddy was that we were now handling three separate entity types, all of which had
different behaviours and functions. This made integration between the three tabs more challenging. As an example, we
were unable to implement the cascading update and delete from the Contacts
tab to the Finance
and Events
tabs
(more on this).
Overall, we felt that we the effort that we have put into creating FreelanceBuddy is more than sufficient. This is justified
by the sheer amount of new features we have added (i.e. all the Finance
and Events
features). We also felt that many
of the features we added (e.g. summary
, filter-t
) were different from all the AB3 features.
Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
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.
For the following tests we assume that you are on the Contacts tab.
Viewing all contacts in FreelanceBuddy
Prerequisites: There are contacts that are already saved in FreelanceBuddy.
Test case: list
Expected: all previously saved contacts will be shown only in the contacts tab. There will be a success message of "Listed all persons".
Test case: list 1234
Expected: all previously saved contacts will be shown only in the contacts tab. There will be a success message of "Listed all persons".
Add a new contact into FreelanceBuddy
Test case (only compulsory fields): add n/‘Chewbaca’ The 1st p/+659123139 e/chewie@gmail.com
Expected: a new contact
with the corresponding details will be added to the bottom of the list.
Test case (with all fields): add n/Annie Dunkins p/+610489630614 e/ann1e@gmail.com a/Opera house c/NAB t/@anniebirds
Expected: a new contact
with the corresponding details will be added to the bottom of the list.
Test case (missing compulsory field): add n/Abbie Dunkins p/+610489630614 a/Opera house c/NAB t/@anniebirds
Expected: No contact
added. Error details shown in the status message. List remains unchanged.
Test case (repeated fields): add n/Abbie Dunkins p/+610489630614 e/ann1e@gmail.com a/Opera house c/NAB c/Atlassian t/@anniebirds
Expected: No contact
added. Error details shown in the status message. List remains unchanged.
Test case (invalid format for one field): add n/Abbie Dunkins p/123 e/ann1e@gmail.com
Expected: No contact
added. Error details shown in the status message. List remains unchanged.
Pre-requisites: Another contact exactly names Annie Dunkins
must exist.
Test case (duplicate name): add n/Annie Dunkins p/+555 555-5555 e/annie@gmail.com
Expected: No contact
added. Error details shown in the status message. List remains unchanged.
Editing a contact in FreelanceBuddy
Pre-requisites: There must be at least one contact that is already saved in FreelanceBuddy and no other contact can have the name ‘Chewbaca’ The 1st
. List all persons using 'list' command.
Test case (valid edit): edit 1 n/‘Chewbaca’ The 1st
Expected: contact at index 1 has name field modified to ‘Chewbaca’ The 1st.
Pre-requisites: Contact at index 1 must have a stored telegram handle.
Test case (removing optional fields): edit 1 n/Alex Yeoh t/
Expected: contact at index 1 has name field modified to Alex Yeoh and telegram handle stored is removed.
Test case (removing compulsory fields): edit 1 n/
Expected: contact will not be edited. Error details shown in the status message.
Other incorrect delete commands to try: edit 1 p/
, edit 1 e/
, edit x t/
(where x is larger than the list size)
Expected: Similar to previous.
Deleting a person while all persons are being shown
Prerequisites: List all persons using the list
command. Multiple persons 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 person 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.
Filter a contact by name
Pre-requisites: There must be at least one contact that is already saved in FreelanceBuddy. Ensure one of them has the name Alex Yeoh
Test case (valid filter): filter-n Alex
Expected: Only contacts with the key word Alex
(not case-sensitive) will be shown in the list.
Pre-requisites: There is no one in FreelanceBuddy that has the name that consist of Alex
Test case (invalid keyword): filter-n Alex
Expected: No contacts are shown in the list.
Test case (without keyword): filter-n
Expected: Error details shown in the status message. List remains the same.
Filter a contact by company
Pre-requisites: There must be at least one contact that is already saved in FreelanceBuddy. Ensure one of them has the company Google
Test case (valid filter): filter-c google
Expected: Only contacts with the key word google
in the company name (not case-sensitive) will be shown in the list.
Pre-requisites: There is no one in FreelanceBuddy that has the company that consist of google
Test case (invalid keyword): filter-c google
Expected: No contacts are shown in the list.
Test case (without keyword): filter-c
Expected: Error details shown in the status message. List remains the same.
For the following tests, we assume that you are on the Finance tab.
Listing all finances in FreelanceBuddy
Prerequisites: We assume that there are multiple expenses and commissions in the finance tab.
Test case: list
Expected: Lists all finances
Test case: list commission
Expected: List all commissions
Test case: list expense
Expected: List all expenses
Adding a commission to FreelanceBuddy
Prerequisites: There has to be at least one client saved in FreelanceBuddy. For our example, we shall assume the client John Doe
exists in our contacts.
Test case: add-c a/900 c/John Doe d/ChatBot commission t/next week
Expected: A new commission
with the corresponding details is added to the list. The amount should be highlighted in green. The time displayed should be a week from the current time.
Test case (no time input): add-c a/50 c/John Doe d/ChatBot commission
Expected: A new commission
with the corresponding details is added to the list. The amount should be highlighted in green. The time displayed should be the current time.
Test case (Amy Smith is not in the contacts): add-c a/50 c/Amy Smith
Expected: No commission
added. Error details shown in the status message. List remains unchanged.
Test case: add-c a/50 c/John Doe
Expected: No commission
added. Error details shown in the status message. List remains unchanged.
Other incorrect delete commands to try: add-c a/50 c/John Doe
, add-c a/-50 c/John Doe d/ChatBot commission
Expected: Similar to previous.
Adding an expense to FreelanceBuddy
Prerequisites: There has to be at least one client saved in FreelanceBuddy. For our example, we shall assume the client John Doe
exists in our contacts.
Test case: add-e a/900 c/John Doe d/ChatBot commission t/next week
Expected: A new commission
with the corresponding details is added to the list. The amount should be highlighted in red. The time displayed should be a week from the current time.
Test case (no time input): add-e a/50 c/John Doe d/ChatBot commission
Expected: A new commission
with the corresponding details is added to the list. The amount should be highlighted in red. The time displayed should be the current time.
Test case (Amy Smith is not in the contacts): add-e a/50 c/Amy Smith
Expected: No commission
added. Error details shown in the status message. List remains unchanged.
Test case: add-e a/50 c/John Doe
Expected: No commission
added. Error details shown in the status message. List remains unchanged.
Other incorrect add-e
commands to try: add-e a/50 c/John Doe
, add-e a/-50 c/John Doe d/ChatBot commission
,
Expected: Similar to previous.
Editing a Finance Entry in FreelanceBuddy
Prerequisite: For our example, we shall assume that the following finances are present in the finance tab:
commission
with the client John Doe
, amount 900
and description ChatBot UI
is at index 1
expense
with the client John Doe
, amount 50
and description Adobe Photoshop subscription
is at index 2
.We also assume that Adam Smith
is in our contacts and Betsy Crowder
is not.
Test case: edit 1 c/Adam Smith
Expected: The client tagged to the commission should now be Adam Smith
. Rest of the commission remains unchanged.
Test case: edit 1 a/100
Expected: The amount is changed to 100
. Rest of the commission remains unchanged.
Test case: edit 1 d/ChatBot commission payment
Expected: The description is changed to ChatBot commission payment
. Rest of the commission remains unchanged.
Test case: edit 1 t/tmr
Expected: The time due is changed to the next day. Rest of the commission remains unchanged.
Test case: edit 1 c/
Expected: No changes to the commission
. Error details shown in the status message.
Test case: edit 1 a/-900
Expected: No changes to the commission
. Error details shown in the status message.
Test case: edit 1 d/
Expected: No changes to the commission
. Error details shown in the status message.
Test case: edit 2 c/
Expected: There is now no client tagged to the expense.
Rest of the expense remains unchanged.
Other test cases: Repeat steps 2-5 for the expense entry (i.e. Replace index 1 with 2)
Deleting a Finance Entry in FreelanceBuddy
Prerequisites: There has to be at least one finance entry saved in FreelanceBuddy, but less than 999. Assuming the client John Doe
exists in our contacts, we can set up an entry with the command add-c d/Test c/John Doe a/20
.
Test case: delete 1
Expected: The entry corresponding to the index 1
is deleted. The index of every entry after 1
is updated to form a continuous list.
Test case: delete 999
Expected: Deletion fails. Error details shown in the status message. List remains unchanged.
Test case: delete 0
Expected: Deletion fails. Error details shown in the status message. List remains unchanged.
Other incorrect delete commands to try: delete -1
, delete 5.99
Expected: Deletion fails. Error details shown in the status message. List remains unchanged.
Filtering finance entries by Client
Prerequisites: There has to be at least one finance entry saved in FreelanceBuddy, but less than 999. Assuming the clients John Doe
and Mary Sue
exist in our contacts, we can set up entries with the commands add-c d/Test c/John Doe a/20
and add-e d/Test2 c/Mary Sue a/50
.
Test case: filter-c john
Expected: Only entries that belong to a client whose name contains john
(case-insensitive) will be displayed. Number of entries shown in the status message.
Test case: filter-c John mary
Expected: Only entries that belong to a client whose names contain John
or mary
(case-insensitive) will be displayed. Number of entries shown in the status message.
Test case (no finance entry has a client with name containing Hello
): filter-c Hello
Expected: No entry will be displayed. Number of entries (0) shown in the status message.
Test case: filter-c
Expected: Filter fails. Error details shown in the status message. List remains unchanged.
Filtering finance entries by Time Frame
Prerequisites: There has to be at least one finance entry saved in FreelanceBuddy. Assuming the client John Doe
exists in our contacts, we can set up entries with the commands add-c d/Test c/John Doe a/20 t/2023-10-10
and add-e d/Test2 c/John Doe a/50 t/2024-10-10
.
Test case: filter-t s/2023-10-09 e/2023-10-11
Expected: Only entries between 2023-10-09
and 2023-10-11
will be displayed. Number of entries shown in the status message. If using the above setup, only the former entry will be displayed.
Test case: filter-t s/2023-10-09 e/2024-10-12
Expected: Only entries between 2023-10-09
and 2024-10-12
will be displayed. Number of entries shown in the status message. If using the above setup, both entries will be displayed.
Test case (no entries in 2099): filter-t s/2099-01-01 e/2099-12-31
Expected: No entry will be displayed. Number of entries (0) shown in the status message.
Test case: filter-t s/test e/test
Expected: Filter fails. Error details shown in the status message. List remains unchanged.
Test case: filter-t s/2023-10-09
Expected: Filter fails. Error details shown in the status message. List remains unchanged.
Test case: filter-t
Expected: Filter fails. Error details shown in the status message. List remains unchanged.
Generating finance summary of a client in FreelanceBuddy
Prerequisites: There has to be at least one client saved in FreelanceBuddy. For our example, we shall assume the clients John Doe
and Mary Sue
exist in our contacts. We can set up entries with the commands add-c d/Test c/John Doe a/20
and add-e d/Test2 c/John Doe a/50
.
Test case: summary John Doe
Expected: Only entries that belong to John Doe
will be displayed. Cumulative value of finance entries, commissions, expenses, and number of commissions and expenses shown in the status message.
Test case (no entries by Mary Sue
): summary Mary Sue
Expected: No entry will be displayed. Status message should be You currently have no finances for this client
.
Test case (Hello
does not exists in contacts): summary Hello
Expected: Summary fails. Error details shown in the status message. List remains unchanged.
Test case: summary
Expected: Summary fails. Error details shown in the status message. List remains unchanged.
For the following tests, we assume that you are on the Events tab.
Viewing upcoming events in FreelanceBuddy
Prerequisites: There has to be at least one event saved in FreelanceBuddy.
Test case: list
Expected: A list of all upcoming events is shown.
Test case: list 123
Expected: A list of all upcoming events is shown.
Viewing all events in FreelanceBuddy
Prerequisites: There has to be at least one event saved in FreelanceBuddy.
Test case: list-all
Expected: A list of all events is shown.
Test case: list-all 123
Expected: A list of all events is shown.
Adding a new event into FreelanceBuddy
Prerequisites: There has to be at least 2 clients saved in FreelanceBuddy. For our example, we shall assume the clients John Doe
and Amy Bee
exists in our contacts.
Test case (only compulsory fields): add n/Dinner s/24-01-2024 20:30 e/24-01-2024 21:30
Expected: A new event
with the corresponding details is added chronologically to the list.
Test case (with all fields): add n/Team meeting s/23-01-2024 19:30 e/23-01-2024 21:30 c/John Doe l/20 Lower Kent Ridge Road, 119080 d/Bring laptop
Expected: A new event
with the corresponding details is added chronologically to the list.
Test case (multiple client input): add n/Yoga s/25-01-2024 12:30 e/25-01-2024 13:30 c/John Doe c/Amy Bee
Expected: A new event
with the corresponding details is added chronologically to the list.
Test case (missing compulsory field): add n/Prepare for exams e/29-01-2024 21:30 c/John Doe l/home d/study on entropy
Expected: No event
added. Error details shown in the status message. List remains unchanged.
Test case (repeated fields): add n/Company party n/Charity run s/19-01-2024 17:30 e/19-01-2024 21:30 c/Amy Bee l/Office d/have fun!
Expected: No event
added. Error details shown in the status message. List remains unchanged.
Test case (invalid date): add n/Baby shower party s/00-01-2024 17:30 e/00-01-2024 21:30 c/Amy Bee l/nana's house d/bring gifts
Expected: No event
added. Error details shown in the status message. List remains unchanged.
Test case (Amy Smith not in contacts): add n/Company Cleanup s/20-01-2024 17:30 e/20-01-2024 20:30 c/Amy Smith l/Office d/bring mop
Expected: No event
added. Error details shown in the status message. List remains unchanged.
Editing an event in FreelanceBuddy
Prerequisites: There exists an event made with the command add n/Dinner s/24-01-2024 20:30 e/24-01-2024 21:30
and its index in the events list is 1
.
There has to be at least 2 clients saved in FreelanceBuddy. For our example, we shall assume the client John Doe
and Amy Bee
exists in our contacts.
Test case (compulsory field edit): edit 1 n/Watch Television
Expected: The event
edited will now reflect the corresponding details.
Test case (optional field edit): edit 1 l/Nacho's Bar
Expected: The event
edited will now reflect the corresponding details.
Test case (multiple client input): edit 1 c/John Doe c/Amy Bee
Expected: The event
edited will now reflect the corresponding details.
Test case (invalid date): edit 1 s/29-01-2024 21:30
Expected: No event
edited. Error details shown in the status message. List remains unchanged.
Test case (repeated fields): edit 1 n/Company party n/Charity run
Expected: No event
edited. Error details shown in the status message. List remains unchanged.
Test case (Amy Smith not in contacts): edit 1 c/Amy Smith
Expected: No event
edited. Error details shown in the status message. List remains unchanged.
Deleting an event from FreelanceBuddy
Prerequisites: There exists an event made with the command add n/Dinner s/24-01-2024 20:30 e/24-01-2024 21:30
and its index in the events list is 1
.
There has to be at least 2 clients saved in FreelanceBuddy. For our example, we shall assume the clients John Doe
and Amy Bee
exists in our contacts.
Test case: delete 1
Expected: The event
deleted will be removed from the list.
Test case (invalid index): delete 0
Expected: No event
deleted. Error details shown in the status message. List remains unchanged.
Filtering events in FreelanceBuddy
Prerequisites: There exists an event made with the command add n/Dinner s/24-01-2024 20:30 e/24-01-2024 21:30 c/John Doe
.
There has to be at least 2 clients saved in FreelanceBuddy. For our example, we shall assume the clients John Doe
and Amy Bee
exists in our contacts.
Test case: filter-n Dinner
Expected: The events list will only show events
with the name Dinner
.
Test case: filter-t 29-01-2024 20:30
Expected: The events list will only show events
before 24-01-2024 20:30
.
Test case: filter-c John
Expected: The events list will only show events
with John Doe
tagged as a client.
Test case (invalid date): filter-t 01230time
Expected: No event
filtered. Error details shown in the status message. List remains unchanged.
Test case (No Event with Amy Bee): filter-c Amy
Expected: The events list will be empty.
Note that the following test cases involves manipulating the JSON files.
The following tests should be performed with the default set of dummy data that is generated when you first open the app (and run at least one command).
Dummy data can also generate by just deleting the json files.
Deleting the JSON files while app is closed
test that deleting json file won't affect other json files
Prerequisites: App must be closed, using dummy data
Delete addressbook.json
, run the app
Expected: Default dummy data for contacts reappears on GUI
Delete addressbook.json
, eventsbook.json
, financebook.json
Expected: Default dummy data for contacts, events, and finance reappears on GUI
Delete addressbook.json
, run the app, and enter list
in any tab
Expected: You should be able to see addressbook.json
regenerate in the file explorer
Deleting the JSON files while app is running
test that deleting the json files while using the app won't cause it to crash
Prerequisites: App must be running, using dummy data
Delete addressbook.json
, then enter command in Contacts tab add n/Test Person p/838383838 e/asdf@gmail.com
Expected: New contact "Test Person" is successfully created and shown in GUI, addressbook.json
regenerates
Delete addressbook.json
, then enter command in Contacts tab filter-n Alex
Expected: Contact "Alex Yeoh" is shown, addressbook.json
regenerates
Delete eventsbook.json
, then enter command in Events tab add n/Test Meeting s/tdy e/tmr
Expected: New event "Test Meeting" is successfully created and shown in GUI, eventsbook.json
regenerates
Delete eventsbook.json
, then enter command in Events tab filter-n Alex
Expected: Event "Meeting with Alex" is shown, eventsbook.json
regenerates
Delete financebook.json
, then enter command in Finance tab add-c d/Painting a/100 c/David Li
Expected: New commission "Painting" is successfully created and shown in GUI, financebook.json
regenerates
Delete financebook.json
, then enter command in Finance tab filter-c Bernice Yu
Expected: All finances regarding "Bernice Yu" is shown, financebook.json
regenerates
Editing contents in addressbook.json
Prerequisites: Default dummy data in addressbook.json
must exists, app is closed
Test case: Edit name in the first entry of addressbook.json
to "poop" and run the app
Expected: Data still exists, first entry name is now "poop". Note that it didn't cause the other two tabs to crash even though Alex Yeoh no longer exists
Test case: Edit name in the first entry of addressbook.json
to an empty string "" and run the app
Expected: All data is erased
Test case: Edit telegram name in the first entry of addressbook.json
to an empty string "" and run the app
Expected: Data still exists, Alex Yeoh now has no telegram name
Test case: Edit telegram name in the first entry of addressbook.json
to "..." and run the app
Expected: All data is erased
Editing contents in financebook.json
Prerequisites: Default dummy data in financebook.json
must exists
Test case: Edit @type in the first entry of financebook.json
to "Expense" instead of "Commission" and run the app
Expected: Finance entry "Artwork" successfully changed from commission to expense
Test case: Edit amount in the first entry of financebook.json
to "0" and run the app
Expected: All data is erased
Test case: Edit client in the third entry(expense) of financebook.json
to null and run the app
Expected: Data still exists, third finance entry now no longer has a client tagged
Editing contents in eventsbook.json
Prerequisites: Default dummy data in eventsbook.json
must exists
Test case: Edit timeStart in the first entry of eventsbook.json
to a date time that is later than timeEnd.
Expected: All data is erased
Test case: Edit timeEnd in the first entry of eventsbook.json
to "tomorrow"
Expected: All data is erased
How to load data from a different file?
Change the file location that you want the app to target through the preferences.json
file. Make sure that it is a valid file path.
Prerequisites: Create your own dummy set of data that is distinguishable to you, and rename the file to something else. Set preferences.json
to target your own dummy files.
Test case: Load data from a different AddressBook file (e.g., addressybooky.json
)
Expected: You should see your own dummy data in the app.
Test case: Load data from a different FinanceBook file (e.g., financeybooky.json
)
Expected: You should see your own dummy data in the app.
Test case: Load data from a different EventsBook file (e.g., eventsybooky.json
)
Expected: You should see your own dummy data in the app.