ExpenseLa Logo

By: Team AY1920S2-CS2103-T09-3      Since: Feb 2020      Licence: MIT

1. Introduction

ExpenseLa is an application for NUS students to be able to track their spending and also gain insights to their monthly spending through data analytics. The data analytics portion of ExpenseLa aims to aid students in viewing and comparing their monthly expenditure on items of different categories such as shopping and groceries, as well as keeping track of their monthly budgets. ExpenseLa records daily incoming and outgoing transactions and constantly keeps track of the user’s budget, income and spending. ExpenseLa is optimised for users who prefer to work with a Command Line Interface (CLI) which works in parallel with a Graphical User Interface (GUI). It is an easy, insight-driven application that hopes to help students keep better track of their expenses.

1.1. Purpose

This developer guide aims to communicate the design and architecture of the software implementation to developers working on ExpenseLa. It also includes future implementations to give developers an idea of the direction that ExpenseLa intends to take on both current and future features. A developer should be able to understand the design, architecture and future goals of ExpenseLa upon reading this guide.

1.2. Scope

This developer guide specifies the technical and non-technical details of ExpenseLa. The technical aspects include the design and architecture of the software and the non-technical aspects include the user stories, use cases and non-functional requirements.

2. Setting up

Pleas refer to the guide here.

3. Design

3.1. Architecture (Pang Kim Jin)

In this section, we will be introducing the individual components that form ExpenseLa using various diagrams.

ArchitectureDiagram
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit diagrams.

Main has two classes called Main and MainApp. It is responsible for,

  • At app launch: Initializes the components in the correct sequence, and connects them up with each other.

  • At shut down: Shuts down the components and invokes cleanup method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

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.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

3.2. UI component (Choi Min Suk)

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, TransactionListPanel, StatusBarFooter etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses 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 does the following actions:

  • Executes user commands using the Logic component.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

3.3. Logic component (Hubert Halim)

LogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

Logic is an interface which LogicManager implements, allowing access to the API. The following items are examples on how the LogicManager class can be interacted with:

  1. Logic uses the ExpenseLaParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a Transaction).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
ClearSequenceDiagram
Figure 7. Interactions Inside the Logic Component for the clear Command

3.4. Model component (Pang Kim Jin)

ModelClassDiagram
Figure 8. Structure of the Model Component

API : Model.java

The Model,

  • stores an ArrayList which contains the user’s command history.

  • stores a UserPref object that represents the user’s preferences.

  • stores the ExpenseLa data.

  • stores the GlobalData which contains the recurring budget, transactions, total balance, and last updated date.

  • stores a MonthlyData object which contains budget, expense, and income information set by the user.

  • stores a ToggleView object that represents the nature of transaction information displayed to the user.

  • stores a Filter object which represents the filter on the transactions as set by the user

  • stores TransactionList which contains the list of all transactions

  • exposes an unmodifiable ObservableList<Transaction> 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.

  • does not depend on any of the other three components.

3.5. Storage component (BenjaminFheng)

StorageClassDiagram
Figure 9. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the ExpenseLa data in json format and read it back.

  • can save GlobalData data in json format and read it back.

3.6. Common classes

Classes used by multiple components are in the seedu.ExpenseLa.commons package.

4. Implementation

This section describes some noteworthy details on how certain features are implemented.

4.1. Adding transactions (BenjaminFheng)

We allow users to add Expense/Income transactions into ExpenseLa which denotes a positive or negative inflow of money. This section shows how we handle these requests from the user.

4.1.1. Implementation

We store every single Transaction added by the user into an ObservableList<Transaction>, which is a list object in TransactionList. We used an ObservableList to easily reflect changes to the list by any other component of ExpenseLa using the list.

These are the ways of implementing either a positive or negative Transaction:

  • Adding an expense (negative transaction): add

  • Adding an income (positive transaction): add i/

These two commands will indicate whether the transaction is positive or negative.

Indicating whether it is a recurring transaction or not will depend if rc/ is present in the input

When inserting a new Expense/Income, the AddCommandParser will determine which object to initialise depending on whether the "i/" CLI syntax is present. Afterwhich, the AddCommandParser will parse the values of the transaction depending on whether the respective CLI Syntaxes are present.

  • Name is parsed by AddCommandParser#parseName(ArgumentMultimap), CLI Syntax is n/.

  • Amount is parsed by AddCommandParser#parseAmount(ArgumentMultimap), CLI Syntax is a/.

  • Date is parsed by AddCommandParser#parseDate(ArgumentMultimap), CLI Syntax is d/.

  • Category is parsed by AddCommandParser#parseCategory(ArgumentMultimap), CLI Syntax is c/.

  • Remark is parsed by AddCommandParser#parseRemark(ArgumentMultimap), CLI Syntax is r/.

  • CLI Syntax "rc/" will set the transaction to be a monthly recurring transaction.

ArgumentMultimap is a class that stores all the parsed parameters taken from the user input.
Category has a set enum list of values FOOD, SHOPPING, TRANSPORT, GROCERIES, HEALTH, RECREATION, MISC, UTILITIES, INCOME.

The following sequence diagram shows how the add transaction operation works:

AddCommandSequenceDiagram

Figure 9. Sequence diagram of how adding a new Transaction is processed depending on syntax.

Transaction are normally instantiated by AddCommandParser#parse(String args), which attempts to parse the various parameters supplied in args and return either a positive or negative Transaction. The following conditions will cause a ParseException to be thrown by the parser:

  • Missing parameters

  • Incorrect syntax (i.e. missing prefix if required)

  • Illegal values in parameters (i.e. special character and symbols entered for an integer only field)

  • Multiple occurence of parameters which only expects single entry

Incorrect user input will display ParseException message.

We will demonstrate how a Transaction is added into ExpenseLa below:

Step 1. The user executes the command add n/Pizza a/20.5 d/2020-02-02 to insert a negative transaction with its Name set to "Pizza", its Amount set to "20.50" and the Date set to 02 Feb 2020. The input is now checked and an attempt to parse each parameter occurs:

Category is set to default category MISC

Since the user input is valid, the Transaction is successfully created and inserted into the transaction list. The transaction list now contains 1 Transaction object.

AddTransactionToList1

Step 2. The user executes add i/ n/Salary a/3000 d/2020-02-03 r/Monthly Salary c/income rc/ to indicate his monthly pay, to insert a positive Transaction.

"rc/" CLI Syntax will set the transaction to be a recurring transaction.

Again, since the input is valid, the positive Transaction is successfully added into the transaction list. The transaction list now contains 2 Transaction objects.

AddTransactionToList2

The following activity diagram summarizes what happens when the user executes a command to add a new Transaction:

AddTransactionActivityDiagram
Figure 10. Activity diagram of adding a Transaction into the transaction list.

4.1.2. Design considerations

There are many different ways to implement how a transaction is added into ExpenseLa. In this section, we will justify why we chose to implement it the way we did.

Aspect: Differentiating between positive and negative transactions.
  • Alternative 1: (current choice): Adding a simple "i/" syntax in the input to differentiate between positive and negative transactions

    • Pros: Increases the speed and simplicity of adding a positive or negative transaction. Updating balance in MonthlyData information only requires an iteration through all the transaction amounts in transaction list for calculation.

    • Cons: Transactions may not be easily distinguishable as positive or negative transactions on first sight, and may only be distinguished when the transaction amount is inspected. This may cause slower processing times when extracting all only positive or only negative transactions.

  • Alternative 2: Having separate classes for positive and negative** transactions.

    • Pros: Maintains an intuitive design: NegativeTransaction deducts money and PositiveTransaction increases money.

    • Cons: May incur significant overhead since it is likely that both NegativeTransaction and PositiveTransaction will have very similar methods.

Alternative 1 was chosen because we want the application to be as simple and quick as possible to indicate positive and negative transactions. We focused on separating the data between months so that the analytics function could calculate data faster.

Aspect: Managing how RecurringTransactions are handled.
  • Alternative 1: (current choice): Adding a simple "rc/" syntax in the input to differentiate between recurring and non-recurring transactions. "rc/" is quickly parsed by the AddCommandParser and the transaction is labelled as recurring, which is added to RecurringTransactionsList before the command is added to the TransactionsList in Model.

    • Pros: "rc/" is quick and intuitive to indicate during input. Almost no hassle to add the information to RecurringTransactionsList.

    • Cons: Inability for existing transactions to set as recurring transactions.

  • Alternative 2: Create a separate command to indicate which transactions are recurring and the range of when it recurs.

    • Pros: Transactions are more customizable for users. Users are able to set recurring transactions to repeat over required months.

    • Cons: Users may easily lose track of the transactions that are recurring which will affect their monthly budgeting.

Alternative 1 was chosen because we want to again keep the recurring transactions intuitive and simple. Users can clear their recurring transaction lists whenever they become invalid, and input the new recurring transactions whenever there are changes

4.2. Editing transactions (BenjaminFheng)

The edit functionality modifies details of a specified Transaction in the existing list and saves modifications to the external storage file.

4.2.1. Implementation

Edit mechanism utilizes Logic operations with the EditCommand class in place of Command, and a unique EditCommandParser class. The following methods are the implementation for edit operations:

  • EditCommandParser#parse() - Parses the user’s input via the index of the transaction and creates an EditCommand to execute the command.

  • EditCommand#execute() - Modifies the Transaction in Model with new details and returns a CommandResult.

  • TransactionList#setTransaction(Transaction target, Transaction editedTransaction) - Sets the modified Transaction to its correct position in the existing TransactionList.

Command example: edit 1 n/[NAME] a/[AMOUNT] r/[REMARK] will edit the name, amount and remark of transaction of index 1 with the respective inputs.

Below is an example usage scenario for editing a transaction and explanation of how the edit mechanism behaves at each step:

Step 1. The user starts up the application with an initial list loaded from a sample transaction list.

editCommand1
Initial transaction list

Step 2. The user inputs edit 1 n/Laksa Noodle a/6.00 to edit the transaction (with index 1) name to "Laksa Noodle" and value to "6". Input is parsed by EditCommandParser#parse() which creates an EditCommand.

Step 3. EditCommand#execute() creates a new transaction that reflects the changes and gets the index of current transaction to be edited.

editCommand2
New edited transaction in transaction list

Step 4. EditCommand#execute() replaces original transaction in the list with the eddited transaction.

The following activity diagram gives an overview of what ExpenseLa shows the user when executing edit command:

EditActivityDiagram
Figure 11. Activity diagram for execution of edit command

4.2.2. Design considerations

This subsection explores some alternative designs considered for certain aspects of the feature’s implementation.

Aspect: Modifying details of a transaction
  • Alternative 1 (current choice): Replace the values of the original transaction with new editd values.

    • Pros: Can easily check for inputs that result in no changes.

    • Cons: May incur overhead when creating new instance of Transaction.

  • Alternative 2: Modify the transaction directly using setter methods.

    • Pros: Easy to implement and efficient.

    • Cons: Modifying transactions violates the immutability principle, possibly resulting in bugs for UI or accessing modified transaction fields.

Alternative 1 chosen to maintain better coding practices and maintain immutability of transactions for the entire project. Overhead of creating new Transaction is insignificant due to relatively small object size.

Aspect: Edit transaction by getting it’s index or by unique transaction ID
  • Alternative 1 (current choice): Get the index of original transaction in the transactions list and edit its values in the list.

    • Pros: High certainty of obtaining the correct transaction, editing its values and replacing the same index in the transaction list.

    • Cons: If there are too many transactions in the list, it might be tedious to obtain the transaction index by scrolling.

  • Alternative 2: Iterate through the transactions list and edit the transaction with the correct transaction ID.

    • Pros: Virtually impossible to not be able to distinguish between similar transactions of different IDs.

    • Cons: Transactions ID would cause significant overhead when looking into each transaction for it’s ID.

4.3. Setting budgets (Hubert Halim)

We allow the user to maintain a Budget for the current month and subsequent months. This section details how ExpenseLa handles requests made by the user who is trying to set a budget both for a one time and recurring budget. Budget is contained inside MonthlyData object along with Expense and Income and application only has 1 MonthlyData object for the current month. object looks like:

BudgetClassDiagram

If user decides to create a recurring budget, there’ll be additional step of updating the recurringBudget variable in GlobalData. BudgetCommand in addition to modifying Budget in MonthlyData, it will also modify recurringBudget in GlobalData.

GlobalDataClassDiagram

4.3.1. Implementation

Whenever the user attempts to set a new Budget, ExpenseLa will create a new MonthlyData object with the given amount. The application will then call ModelManager#setMonthlyData(MonthlyData toSet). During the creation of the new MonthlyData, the Budget class will internally check if the budget amount is valid.

We will demonstrate what happens at the back-end whenever the user sets a budget:

Case 1. The user wishes to set their budget to $1500, non-recurring. They execute the command: budget b/1500. The user’s entry is checked by BudgetCommandParser#parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

  • rc/ prefix does not exist, so it is not recurring

ArgumentMultimap is a class that stores all the parsed parameters taken from the user input.

Since the user input is valid, the Budget is successfully created and inserted into a newly created MonthlyData.

Case 2. The user made a typo when setting their budget. They execute the command budget b/1500. The user’s entry is checked by BudgetCommandParser#parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

Budget class then is attempted to be created with the parsed budget amount in the constructor. Internally Budget will do a validity check using Regex and throw a ParseExection since amount is not valid.

Case 3. The user wishes to set their budget to $1500, recurring. They execute the command: budget b/1500 rc/. The user’s entry is checked by BudgetCommandParser#Parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

  • rc/ prefix exists, so it is recurring

Since the user input is valid, the Budget is successfully created and inserted into a newly created MonthlyData. BudgetCommand will then modify GlobalData in Model by calling Logic#setGlobalData. RecurringBudget value in GlobalData is now set to the new Budget

The sequence diagram below depicts what was just elaborated:

SetBudgetSequenceDiagram
Figure 12. Sequence diagram showing how a Budget is set
SetBudgetActivityDiagram
Figure 13. Activity diagram showing how a Budget is set

4.3.2. Design considerations

We have considered various ways as to how Budget should be stored in ExpenseLa. In this section, we will explain the rationale on our course of actions.

Aspect: Make Budget a part of a bigger class called MonthlyData
  • Alternative 1 (current choice): Budget is a part of MonthlyData and any Budget operations is through MonthlyData

    • Pros: Easier to handle Budget together with other MonthlyData objects and all data inside is synchronised as it is handled by a single object.

    • Cons: Overhead when modifying Budget as to maintain immutability, a new MonthlyData object has to be created.

  • Alternative 2: Budget should be an independent class with a direct reference in ExpenseLa.

    • Pros: More freedom and efficiency in doing modifications on Budget

    • Cons: Need to maintain more references for all different objects.

Again, we went with alternative 1 because it is easier to view Budget along with the other MonthlyData components as a collective. And easier to just handle 1 reference in ExpenseLa.

4.4. Command History navigation (Hubert Halim)

Users can navigate to previous commands by pressing the up or down button on the keyboard. Only successful commands are stored in the CommandHistory list and only a maximum of 50 commands can be stored at a time.

4.4.1. Implementation

Every time the user key in a command and press Enter, CommandBox#handleCommandEntered method will be called. The method will attempt to execute the command by calling CommandExecutor#execute method. That method throws an error if command is invalid. So if the command is valid, the CommandBox#handleCommandEntered method will call Logic#deleteCommandFromHistory to delete the command if it exists in the current command history. It will then call Logic#addToCommandhistory to add the command to the command history as its latest entry. Both commands for add and delete takes in an integer variable called offset. This variable is maintained by CommandBox and determines which command the user is currently at in the command history. Offset starts from -1 indicating CommandBox is empty and resets to -1 every time a successful command is entered

Command History is an array list that resides in ModelManager object. It can be accessed through Logic by calling

The diagrams below depicts what was just elaborated:

CommandHistorySequenceDiagram
Figure 14. Sequence diagram showing what happens when user enters a Command
CommandHistoryActivityDiagram
Figure 15. Activity diagram showing what happens when user enters a Command
CommandHistoryNavigateSequenceDiagram
Figure 16. Sequence diagram showing what happens when presses Up/Down button
CommandHistoryNavigateActivityDiagram
Figure 17. Activity diagram showing what happens when presses Up/Down button

4.4.2. Design considerations

We have considered various ways as to how to implement CommandHistory to support navigation to previous commands Since we need to capture keyboard events when user press the keyboard, we decided to implement the event listener and handler in CommandBox component as it is more convenient because when a keyboard event is captured, the app can straight away modify the TextField in CommandBox. Since the event when user enter a command is also handled in CommandBox and we only store successful commands in CommandHistory, we wait for execution of the Command by CommandExecutor, if it is successful, the String for the command is added to, otherwise due to the error thrown and caught somewhere else, the command is not stored.

4.5. Filtering Transactions (Pang Kim Jin)

The Filter command allows the user to bring up a list of Transaction, and filter it by either category, month, or both at the same time. This is implemented by using a predicate for category and another predicate for month, both of which inheriting from Predicate<Transaction> to filter the Transaction.

4.5.1. Implementation

FilterCommand is instantiated by FilterCommandParser#parse(String args) method, which parses the arguments supplied in the user command to return a FilterCommand object.

The below sequence diagram depicts the interactions within the Logic component for the execute("filter c/FOOD m/2020-04") call: FilterSequenceDiagram

The below scenario shows a typical usage of the filter feature:

Step 1: Upon application launch, the filter for all categories and the current month is automatically applied. Filter SS 1

Step 2: User executes the command filter c/food m/2020-02 to bring up transactions in the category "FOOD" for the month of February 2020. (Note: The command in the command line disappears upon hitting Enter, the command in the command line is purely for illustration purposes). Filter SS 2

Step 3: The FilterCommandParser#parse(String args) parses the arguments.

Step 4: Since user input is correct and the arguments are parsed, a new FilterCommand object is created by the FilterCommandParser.

Step 5: The FilterCommand object will use a Predicate<Transaction> based on the specified category, month, or both, to filter the list of transactions.

Step 6: The list of filtered transactions is brought up. The filter category and month UI will also update accordingly to show the category and month that the transactions are filtered by.

The below activity diagram gives an overview of the command execution: FilterActivityDiagram

4.5.2. Design Considerations

Aspect: Using Predicate to improve extendability of the Filter feature in the future.

  • Alternative 1 (current choice): Create a new Predicate<Transaction> for each new filter type

    • Pros: Greater flexibility can be provided for each filter type since different filter types have different requirements (e.g. Month vs Category)

    • Cons: Tedious to implement a new class for each new type of filter

  • Alternative 2: Use a single Predicate<Transaction> to filter for all filter types

    • Pros: Easy to implement

    • Cons: Prone to being inflexible for extensions

We decided to go with Alternative 1 since the current filter feature supports increasing the number of filter types - on top of the current category and month filters. Despite having a different Predicate for each filter type, we use a composed Predicate comprising of both Predicate s, making it much easier to support extensions to this feature.

4.5.3. Proposed Extension

We plan to enhance the filter feature to support other arguments in the command to filter by different types such as price range or date range. This allows the user to have greater flexibility and have a better understanding of his/her expenses.

The design consideration mentioned earlier hence facilitates this proposed extension, reducing the difficulty of such a future implementation.

4.6. Chart Analytics (toggleview Command and Bar Graphs by Choi Min Suk + Pie Chart by Pang Kim Jin)

The toggleview command allows the user to switch between viewing the list of 'Transactions' and viewing an analysis of his expenditure.

In the expenditure analysis view we have a bar chart to show expenditure breakdown by date as well as a pie chart to show expenditure breakdown by category.

4.6.1. Implementation

MainWindow decides whether to show a list of transactions or chart analysis based on ToggleView#isViewList, by accessing Logic#getToggleView().

Here is a Class Diagram for the implementation of ToggleView:

ToggleViewClassDiagram

The ToggleView mechanism utilizes Logic operations with the ToggleViewCommand class in place of Command. The following methods are concrete implementations for the toggle operation:

  • ToggleViewCommand#execute() - Modifies the ToggleView in Model to view list of transactions or view analytics, and returns a CommandResult (Step 4 of Logic).

  • ToggleView#switchIsViewList() - Modifies the boolean value isViewList in ToggleView to the negation of it’s current value.

    • This ToggleView is wrapped in ExpenseLa and its switchIsViewList() is called through ExpenseLa#switchToggleView().

    • ExpenseLa#switchToggleView() is exposed in the Model interface as Model#switchToggleView().

The following sequence diagram illustrates toggleview command execution:

ToggleViewSequenceDiagram
Figure 18. Sequence diagram showing execution of toggleview
Example of usage

Given next is an example and explanation of how the ToggleView mechanism behaves at each step:

Step 1. The user starts up the application with an initial list loaded from external storage file. The diagram here depicts the example list used throughout this scenario.

ToggleViewStep1
Example list on startup

Step 2. The user inputs toggleview to change the view from list of transactions to chart analysis.

ToggleViewStep2
User input for toggle view

Step 3. ToggleViewCommand#execute() switches isViewList of ToggleView from true to false.

ToggleViewStep3
isViewList of ToggleView switched from ToggleViewCommand#execute()

Step 4. MainWindow#executeCommand() checks the boolean value of isViewList in ToggleView, which is false, and displays chart analysis.

ToggleViewStep4
Switched from showing list of transactions to chart analysis

Step 5. User inputs toggleview again to change view back to list of transactions.

ToggleViewStep2
ToggleViewStep1
Switched from showing list of transactions to chart analysis

Step 6. User can set filter to a certain month to view a different kind of bar chart.

ToggleViewStep6
Example of stacked bar chart of expenditure for a certain month

The following code snippet from MainWindow#executeCommand() checking of the boolean value of isViewList in ToggleView, and deciding whether to show a list of transactions of chart analysis, and what bar graph to show:

MainWindow#executeCommand()
// The if else statement checks the value of isViewList from ToggleView
if (logic.getToggleView().getIsViewList()) {
    // Creates ui for list of transactions
    transactionListPanel = new TransactionListPanel(logic.getFilteredTransactionList());
    transactionListAndChartAnalyticsPanelPlaceholder.getChildren().add(transactionListPanel.getRoot());
} else {
    // Creates ui for chart analysis
    // Calls logic.getIsFilterMonth() to check if the filter is set to a specific month or not, to decide which bar graph to build
    chartAnalyticsPanel = new ChartAnalyticsPanel(logic.getFilteredTransactionList(), logic.getIsFilterMonth());
    transactionListAndChartAnalyticsPanelPlaceholder.getChildren().add(chartAnalyticsPanel.getRoot());
}
Execution shown to user

The following activity diagram gives an overview of what ExpenseLa shows the user when executing toggleview command:

ToggleViewActivityDiagram
Figure 19. Activity diagram for execution of toggleview command

4.6.2. Design considerations

This section shows some of the design considerations taken when implementing the undo and redo features.

Aspect: Design used to implement toggelview feature
  • Alternative 1 (current choice): Create a ToggleView Class to keep a boolean value of isViewList to keep track of showing list of transactions or chart analysis.

    • Pros: Easily extendable next time to accommodate more different kind of views by changing boolean to possibly enum.

    • Pros: Easy to implement functions to change values in ToggleView object, which allows easy extendability next time also.

    • Cons: Needs to implement many functions through Logic and Model.

  • Alternative 2: Create a boolean value in Model to track whether to show list of transactions or chart analysis.

    • Pros: Easy implementation and checking of boolean value by MainWindow to check which view to show.

    • Cons: Not extendable next time when trying to accommodate different kind of views.

Alternative 1 was chosen because it is easily extendable, in case we want to improve or develop on the feature in the future. It also follows better OOP principles, making the code much neater and understandable.

4.7. Export (Choi Min Suk)

The export command allows user to export currently filtered transactions to a csv file, in case he would like to use the data for his own analysis.

4.7.1. Implementation

ExportCommand is instantiated by ExpenseLaParser#parseCommand(String userInput), which attempts to split the userInput into the command word and its parameters. Since ExportCommand does not require any arguments, it is instantiated directly.

ExportCommand obtains the filtered list of transaction to export using Model#getFilteredTransactionList(), which then attempts to create a csv file in the current directory using the attributes of each transaction.

The sequence diagram below shows how the execution of export is like:

ExportSequenceDiagram
Figure 20. Sequence diagram of how export command is applied at the back-end.

The following conditions will cause a CommandException to be thrown by the command:

  1. Empty filtered transaction list

  2. Failure in creating the file

  3. Failure in writing to the file (Possibly due to the directory changing while the command is being executed)

The image below shows how the csv file looks when user executes export command successfully:

ExportCsv
Figure 21. List of transactions in a csv file opened in Microsoft Excel

4.7.2. Proposed extension

In the near future, we plan to enhance the export feature. We want to improve the export command to take in view as a possible argument, thus allowing the user to choose between exporting list of transactions or the chart analysis. The user can use the chart analysis generated for visual presentations, especially if the expense tracker is for a business.

The image below shows how a possible future implementation of this feature could look like:

ExportChartCommand
Figure 22. Expected command to export chart analytics
ExportBarGraph
ExportPieChart
Figure 23. Expected images to be exported when export chartanalysis

4.8. [Proposed] Data Encryption (Pang Kim Jin)

Given the sensitive nature of the information provided by users, we would like to safeguard the information provided by our users through encryption. Naturally, the information would be encrypted and decrypted in the back-end without the user requiring to do any of the encryption, decryption, or even any knowledge of how it works.

4.8.1. Proposed Implementation

We thus propose a Keystore module to contain authorisation certificates or public key certificates interacting with the Logic and Storage modules. With this addition, the following architecture diagram gives an overview of how it would fit in:

DataEncryptionClassDiagram

The Keystore module would have a KeystoreManager which implements the following methods:

  • KeystoreManager#setCipher(Cipher cipher) - sets the Cipher for encryption usage.

  • KeystoreManager#encryptExpenseLa(ExpenseLa expenseLa) - encrypts the given ExpenseLa object with the encryption cipher set with every call to LogicManager#execute() method.

  • KeystoreManager#decryptExpenseLa(ExpenseLa expenseLa) - Decrypts the encrypted json file upon application launch.

The following class diagram provides a depiction of the above:

DataEncryptionClassDiagram2
KeystoreManager#encryptExpenseLa(ExpenseLa expenseLa) and KeystoreManager#decryptExpenseLa(ExpenseLa expenseLa) will be using the Advanced Encryption Standard (AES 256) encryption algorithm.

4.8.2. Design Considerations

Aspect: Encryption Algorithm

  • Alternative 1: Data Encryption Standard

    • Pros: Simpler to implement encryption and decryption

    • Cons: Weaker security, easy to brute force

  • Alternative 2 (current choice) : Advanced Encryption Standard

    • Pros: 256 bit key is exponentially more secure than DES' 56 bit key

    • Cons: Harder to implement

4.9. [Proposed] ExpenseLa Monthly Statement (Pang Kim Jin)

Similar to how banks issue a statement of account, we believe that it would be helpful to provide our users with an overview of their expenses. This statement would include the user’s balance, budget, expense, income, and transactions in a user specified time frame.The user can choose to include/exclude certain transactions based on their categories or dates.

4.9.1. Proposed Implementation

To generate the statement, we propose a StatementCommand that extends Command and works with ModelManager just like all other commands, as depicted in the following diagram:

StatementCommandClassDiagram
  • The user uses the FilterCommand to filter the list of transactions to show only the transactions with the user’s preferred category and transaction month

  • Then StatementCommand#execute() will retrieve the FilteredList of transactions and generate a Portable Document Format (PDF) file with Java’s PDFWrite API.

Below is a truncated example of the PDF ExpenseLa statement:

Statement

4.9.2. Design Considerations

Aspect: Time and Nature of Transactions to Export

  • Alternative 1 (current choice): Users get to choose when to generate their statement and which month and categories of transactions to include.

    • Pros: Users get a statement tailored according to their needs.

    • Cons: Users may forget to include certain types of transactions.

  • Alternative 2: At the end of every month, a statement of all transactions and user information is exported

    • Pros: Users get a comprehensive view of their expenses

    • Cons: Users may be overloaded with information

Ultimately we chose Alternative 1 as we prioritise our user’s freedom of choice and we understand that not all transactions may be relevant for the purposes of exporting the statement.

4.10. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 4.11, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

4.11. Configuration

Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).

5. Documentation

Refer to the guide here.

6. Testing

Refer to the guide here.

7. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to keep track of their expenses

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: efficient way to keep track of expenses and make decisions based on data and analytics provided

Appendix B: User Stories

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

* * *

general user

add a new expense entry

keep track of my expenses

* * *

employed user

add a new income entry

keep track of my income

* * *

high-income user

keep track of all the money I earn

make decisions on where my most lucrative source of income is

* * *

low-income user (like student)

set budget for current month

limit my expenditure for the month

* * *

low-income user (like student)

be notified by the application if i am spending too much money

be wary of overshooting my budget

* * *

consistent thrifty user

set budget for every month(recurrent budget) once

have no need to constant;y set my unchanging budget

* * *

part-time worker with varying income

be flexible with my budgets

spend more or less on certain months depending on my financial situation

* * *

visual user

be visually alerted when I spend a certain proportion of my budget

adjust my spending habit for the rest of the month

* * *

careless user

delete an expense or income entry

remove entries that I added in by mistake

* * *

forgetful user

find an entry by keyword

check if I spent money on a particular thing

* * *

spendthrift user

filter expense based on category

know if I generally spend a lot of money or only on certain months

* * *

forward-looking user

look at my spending trend by week or month

keep track of my income

* * *

couple/student trying to save up

filter expense based on date or time period

see how much money I have spent in that time period and make better decisions

* * *

couple/student trying to save up

view amount of budget left to spend

adjust spending habit for the rest of the month

* * *

general user

view total money I have

be able to tell how much I can spend

* * *

user trying to save money

view total expense for a particular month

decide on my future expenditures

* * *

visually analytical user

view pie chart of money spent based on category

see where I spend the most money on

* * *

visually analytical user

view bar chart of money spent based on time period

see when I spend the most money

* * *

organized user

organize my expenditure into different categories

better able to track where I am spending my money

* * *

not one-off user

all my expenditures and income to be saved

continue on from previous whenever I exit and launch back the application

* *

smart analytical user

export my expenditure and income

use the data to make my own analysis

* *

secretive user

set a password to login tp the application

prevent unwanted users from viewing my expenses

* *

businessman

have multiple accounts

manage my expenses not only for myself but my business

* *

parent

have multiple accounts

help manage my children’s expenses

* *

user with many friends

add friends in the application

help each other in their savings

* *

concerned friend

look at my friend’s spending habit

keep a lookout for their expenditure

*

user who owes people money

view the people who I owe money to

keep track of who I owe

*

user who lends people money

request payment from people who owe me money

keep track of my loans

*

sociable user

indicate when my expenditure is within the budget

share the achievement with my friends

*

lazy user

have the application make recommendations on my spending habits

Appendix C: Use Cases (Hubert Halim)

(For all use cases below, the System is the ExpenseLa and the Actor is the user, unless specified otherwise)

Use case: Delete expense

MSS

  1. User requests to list all transactions

  2. System removes all filters and show all expenses

  3. User requests to delete a specific transaction in the list

  4. System deletes the transaction

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

Use case: filter transactions by category

MSS

  1. User requests to list filtered transactions

  2. System queries list of transactions

  3. Apply filter predicate to update list of filtered transactions

  4. System shows filtered list

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The category given is not valid.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

Use case: Set recurring monthly budget

  1. User requests to set a recurring budget of a specified amount.

  2. ExpenseLa processes the request and sets the specified amount as the budget for the current month.

  3. ExpenseLa then update the value of recurringBudget variable in GlobalData to the specified amount.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. ExpenseLa displays an invalid parameter error to the user and the monthly budget is not updated.

      Use case ends.

Use Case: Add an expense

MSS

  1. User requests to add a new expense into their expensela.

  2. The system processes the request and adds the expense transaction into the transactions list.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. The system displays an invalid parameter error to the user and the transactions list is not updated.

      Use case ends.

Use Case: Add a recurring income

MSS

  1. User requests to add a new recurring income into their expensela.

  2. The system processes the request and adds the income transaction into the transactions list.

  3. The system then add the income transaction to RecurringTransactionList in GlobalData.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. The system displays an invalid parameter error to the user and the transactions list is not updated.

      Use case ends.

Use Case: Show chart analytics view

MSS

  1. User requests to toggle to chart analytics view.

  2. The system switches the view to charts view.

    • 2a. The filter for month is set to all, bar chart displays data of the last 2 years by month.

    • 2b. The filter for month is set to a specific month, bar chart displays data by day of the week.

      Use case ends.

Use Case: Clear transaction list

MSS*

  1. User requests to clear all transactions.

  2. The system clears transaction list in ExpenseLa.

  3. The system resets MonthlyData and GlobalData

    Use case ends.

Use Case: Export to CSV file

MSS

  1. User requests to export current list being viewed to a CSV file.

  2. The system saves the transactions to that csv file named transactions.csv by the system.

Use case ends.

Extensions

  • 1a. The file does not exists.

    • 1a1. The system creates a file with the name transactions.csv.

      Use case resumes at step 2.

Use Case: Import from CSV file

MSS

  1. User requests to import transaction data from a CSV file.

  2. Import the transactions data from the file specified by the user ignoring duplicate and invalid transactions

    Use case ends.

  • 1a. The file specified by user does not exists.

    • 1a1. The system shows an error message prompting user to rectify their command.

      Use case ends.

Use Case: Find transactions whose name contains certain words

MSS

  1. User requests to list transactions whose name contains certain words.

  2. The system queries all transactions

  3. The system applies predicate to filter only transactions that contain the words specified by user

    Use case ends.

  • 2a. The list is empty.

    Use case ends.

  • 3a. The list is empty.

    Use case ends.

Appendix D: Non Functional Requirements (Pang Kim Jin)

  1. The software should work on any mainstream OS as long as it has Java 11 or above installed.

  2. The software should be able to hold up to 2000 transactions(expenses and incomes).

  3. The software should be able to respond within 5 seconds.

  4. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.

  5. The software should be able to run irrespective of internet connection.

  6. The software should support both manual and automated testing.

  7. The source code should be open-source

Appendix E: Glossary

ExpenseLa

Stands for the application that this developer guide is written for.

API

Stands for "Application Programming Interface" which simplifies programming by abstracting the underlying implementation and only exposing objects or actions the developer needs.

PlantUML

Stands for a software tool that we use to render the diagrams used in this document.

Mainstream OS

Stands for commonly used Operating Systems (OS) such as Windows, Linux, Unix, OS-X

System Administration

Stands for the field of work in which someone manages one or more systems, be they software, hardware, servers or workstations with the goal of ensuring the systems are running efficiently and effectively.

MSS

Stands for Main Success Scenario that describes the interaction for a given use case, which assumes that nothing goes wrong.

CLI Syntax

Stands for the Command Line Interface Syntax such as "a/" and "c/" that preceeds input values which act as indicators for the system to detect those values.

UI

Stands for the user interface which is the display which interacts with the user.

Appendix F: Product Survey

ExpenseLa

Author: Team Halim

Pros:

  • Very easy and quick tracking for people that prefer command line interfaces.

  • Analytics serve as a quick bird’s eye view on monthly spending.

  • Analytics breakdown of spending per category helps me gain insights on the categories which I have spent too much money on.

  • Well made prompts to warn me when I am going to exceed my monthly budget. Helps to better my budgeting practices.

Cons:

  • Takes quite a bit of time to learn all the commands.

  • It can get quite tedious to input every single transaction at any time. Could possibly automate some inputs.

Appendix G: Instructions for Manual Testing (Pang Kim Jin)

Given below are instructions to test the app manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

G.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

G.2. Setting a monthly budget

  1. Setting a monthly budget to a user decided amount

    1. Test Case: budget b/1000
      Expected: The monthly budget for the current month is set to $1000

    2. Test Case: budget
      Expected: The monthly budget is not updated. Error is shown in the status message

G.3. Resetting total balance

  1. Reset Balance value to the total from the amount of all transactions stored

    1. Test Case: resetBalance
      Expected: The Balance is reset

G.4. Adding a transaction

  1. Add either an expense or income transaction

    1. Test Case: add a/ 26.00 n/ Grab Share d/ 2020-02-19 c/ TRANSPORT
      Expected: A new expense transaction is added to the transaction list. Depending on the current filter applied this change may or may not be visible. Details of the added transaction is visible in the Command Result

    2. Test Case: add a/ 16.00 n/ Pizza r/ Lunch c/ FOOD
      Expected: A new expense transaction is added to the transaction list, with the transaction date set to the current date. Details of the added transaction is visible in the Command Result

    3. Test Case: add i/ a/ 200.00 n/ pocket money c/INCOME rc/
      Expected: A recurring income transaction is added to the transaction list, with the transaction date set to the current date. Details of the added transaction is visible in the Command Result

    4. Test Case: add i/ n/ allowance c/INCOME rc/
      Expected: No transaction is added. Error details are shown in the Command Result

G.5. Filtering transactions

  1. Filtering transactions listed by category, month, or both.

    1. Test Case: filter m/2020-04
      Expected: A month filter for April 2020 is applied to the transaction list, relevant transactions are listed. Details of the number of transactions found is visible in the Command Result

    2. Test Case: filter c/TRANSPORT
      Expected: A category filter for "TRANSPORT" is applied to the transaction list, relevant transactions are listed. Details of the number of transactions found is visible in the Command Result

    3. Test Case: filter c/FOOD m/2020-02
      Expected: A category filter for "FOOD" and month filter for February 2020 is applied to the transaction list, relevant transactions are listed. Details of the number of transactions found is visible in the Command Result

    4. Test Case: filter
      Expected: No filter is applied and no transactions listed. Error details are shown in the Command Result.

G.6. Deleting a transaction

  1. Deleting a transaction from the transactions listed

    1. Prerequisites: At least one transaction in the list using either list or filter command.

    2. Test case: delete 1
      Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message.

    3. Test case: delete 0
      Expected: No transaction is deleted. Error details shown in the status message.

    4. Test Case: delete
      Expected: No transaction is deleted. Error details are shown in the Command Result.

G.7. Editing a transaction

  1. Editing a transaction from the transactions listed

    1. Prerequisites: At least one transaction in the list using either list or filter command.

    2. Test case: edit 1 a/ 26.00 n/ Grab Share d/ 2020-02-19 c/ TRANSPORT
      Expected: First contact is edited from the list. Details of the edited contact shown in the status message.

    3. Test case: edit 0 a/ 26.00 n/ Grab Share d/ 2020-02-19 c/ TRANSPORT
      Expected: No transaction is edited. Error details shown in the status message.

    4. Test Case: edit a/ 26.00 n/ Grab Share d/ 2020-02-19 c/ TRANSPORT
      Expected: No transaction is edited. Error details are shown in the Command Result.

G.8. Analysis of transactions

  1. Toggle between viewing list of transactions and analytics with bar graph and pie chart to show expense trend.

    1. Test case: toggleview
      Expected: Transaction view is toggled to analytics view or vice versa.

    2. Test case: toggle
      Expected: No toggling happens. Error details shown in the status message.

G.9. Finding transactions

  1. Finding transactions that match any of the supplied keywords in its name field.

    1. Test case: find Airpods
      Expected: Transactions with the word "Airpods" in its name will be displayed in the transaction list.

    2. Test case: find Airpods Allowance Electricity
      Expected: Transactions with the word "Airpods" "Allowance" or "Electricity" in its name will be displayed in the transaction list.

    3. Test case: find
      Expected: No transactions found. Error details shown in the status message.

G.10. Listing all transactions

  1. Listing all transactions and resetting all filters to "ALL".

    1. Test case: list
      Expected: All transactions will be displayed in the transaction list. Filter for Category and Month are now "ALL".

G.11. Clearing all recurring transactions

  1. Clearing all recurring transactions stored.

    1. Test case: clearrecurring
      Expected: All recurring transactions in the transaction list will be cleared.

G.12. Exporting transaction data to csv

  1. Exporting the filtered transaction list to a csv file.

    1. Prerequisite: There must be at least one transaction in the transaction list

    2. Test case: export
      Expected: All transactions in the transaction list after applying filters will be exported.

G.13. Importing transaction data from csv

  1. Importing the filtered transaction list to a csv file.

    1. Prerequisite: There must be at least one transaction in the csv file

    2. Test case: import transactions.csv
      Expected: All transactions that are in the correct format and not duplicated entries in the transactions.csv file will be imported.

G.14. Clearing all data

  1. Clearing all data in ExpenseLa including monthly data and global data

    1. Test case: clear
      Expected: All transactions are deleted, balance is set to 0 and monthly data is also set to 0. All recurring data such as budget and transactions are also cleared.

G.15. Showing help window

  1. View the help window for help with commands

    1. Test Case: help
      Expected: A popup with a link to the User Guide pops up.

G.16. Saving data

  1. Dealing with missing/corrupted data files

    1. Delete the data files at .\data\expenseLa.json and .\data\globalData.json

Appendix H: Effort

In this section, we highlight the amount of effort taken for us to develop ExpenseLa, the challenges faced in this development and our eventual achievement.

H.1. Effort by team

Our application, ExpenseLa, is considerably different from what Address Book 3 (AB3) had implemented. We wanted to take some address book features that were available in AB3, but wanted to build an expense tracker for our project. As such, to build ExpenseLa, we took and modified some features previously available in AB3, but had to create many of our own models and implementations for the new features.

In short, AB3 stores details related to multiple people known to the user. ExpenseLa stores data related to multiple transactions by the user and so much more. ExpenseLa uses that data to track the monthly expenditure, income as well as budget, analyses their expenditure by graphing it out, and provide many other features like filtering transactions as well as new ways of adding transactions to make the application easier to use.

While building ExpenseLa, we spent a considerable amount of time not just implementing our features, but also making sure that new features were linked to ExpenseLa and could cohesively work with other features to make sure the application provided and smooth and consistent user experience. All these discussions were held at least once a week with a minimum 2 hours each round to provide feedback for each other’s implementations and that our implementations could work together.

H.2. Challenges faced

The team encountered some challenges while developing ExpenseLa. The most notable ones are:

  • Initial brainstorming of ideas
    At the start of the project, we wanted to do a meeting scheduler for NUS computing students. However after multiple discussions, we deemed it unfit to implement as there were too many components to think about and difficult to implement given our limited time to complete the application. Thus we decided to make an expense tracker instead. We had many different ideas for our expense tracker and ways to implement them. We needed a few meetings to discuss and iron out our direction for the project to ensure everyone was on the same page before starting the development process.

  • Storage
    We needed a way to store our data so when the application starts we can load previously stored transactions and other data. We decided to adopt and modify slightly AB3’s storage system and implement it in ExpenseLa.

  • Commands
    An expense tracker requires many different commands to carry out many different actions, especially since it uses command line interface. We adapted AB3’s parser. For similar commands to AB3 like add, we had to change the command to accept different predicates, thus parsing it differently. We also had to think about how to parse new commands, such as filter function and parsing recurring budget and transactions to be stored as Global data (talked about below), which was a big change from AB3.

  • Global data
    We set ExpenseLa to be timeframe specific, with Monthly Data such as budget, income and expenditure for the month to reset at the beginning of every month. However we also had some data that were not timeframe specific, such as transactions and budget that were set to be recurring every month. We could not store and reference it the same way as how the normal transactions were referenced from the json data. After discussion, we decided to create a GlobalData class in ModelManager where it will be referenced separately from ExpenseLa.

  • User interface
    We decided to keep a ExpenseLa’s UI generally similar to AB3, but with addition of new UI features. We created a new placeholder for Monthly Data for easy constant viewing by the user. We created a chart analysis for the expenditures, which was in the form of a bar chart and pie chart. The charts took up a considerable amount of space, and putting a separate placeholder for it would be unfeasible for small screens. Thus we implemented a toggleview command which allows the user to toggle between viewing the list of transactions and the chart analytics. This required us to learn both the chart libraries as well as think about how we were going to change the views, while updating the charts when new commands were added.

Conclusion
From planning to documentation to coding of the project, the team believes that every member has put in equal and huge amount of effort on all parts of the project. We believe that our product is significantly different from AB3, with many new features which were carefully planned in implementation, and we are proud of ExpenseLa we have built.