cOOPer

cOOPer

Developer Guide

Introducing cOOPer

Welcome to cOOPer’s Developer Guide!

cOOPer is a Command Line Interface (CLI) desktop application developed to simplify administrative processes of tech startups such as communication and finance management.

cOOPer was developed in Java 11 following an Object-Oriented Programming (OOP) paradigm, hence the letters OOP in its name.

This developer guide is for software designers, developers, and software testers of cOOPer. It will be your reference manual if you are looking to:

What’s in this Developer Guide

How this Developer Guide Works

Throughout this developer guide, you will see text formatted differently from normal text, as well as symbols appearing before another line of text. The table below explains the formatting and symbols in this developer guide.

Formatting/Symbol Meaning
italics Text in italics represent terminology specific to using / developing cOOPer.
bold Text in bold emphasizes the text’s importance and indicates that you should pay more attention to the text.
code Short lines of text highlighted as such indicate a class, method, component or user input.
It is also used to represent directories / file paths.
ℹ️ The info symbol indicates useful information about diagrams / content in this developer guide.
💡 The light bulb symbol indicates a useful tip which eases the development of cOOPer.

⬆️ Back to top

Acknowledgements

This section includes the sources of code, documentation and third-party libraries reused / adapted in developing cOOPer.

  1. The dopsun chatbot-cli is a third-party library used to ease the parsing of user input.
  2. The implementation of the Storage component was adapted from one of our member’s CS2113T Individual Project (iP). A few of the methods for file reading and file creation were reused.
  3. The implementation of the PBKDF2 algorithm for storing passwords was adapted from this website. The two methods for generating the hash as well as obtaining the salt were reused, but tweaked slightly in our implementation.
  4. The method used to convert an input stream to a file in Util.java was adapted from this website.
  5. The method used to make a POST Request to an online LaTeX compiler for the generate feature was adapted from this website.
  6. JUnit 5 is a third-party library used to perform software testing for cOOPer.

⬆️ Back to top

Setting Up and Getting Started

💡 These are the software / tools used in developing cOOPer. You are recommended to use them too:

Setting up cOOPer on your computer

  1. Fork this repo and clone the fork into your computer.
  2. If you are using IntelliJ IDEA, ensure that IntelliJ is configured to use JDK 11. You can refer to IntelliJ’s own documentation here to correctly configure the JDK.
  3. Import the project as a Gradle project. You can follow this guide to find out how to import the project into IntelliJ.
  4. Verify the setup by running cooper.Cooper
    1. Navigate to src/main/java/cooper/Cooper.java
    2. Right click on Cooper.java and select ‘Run Cooper.main()’.
    3. You should see the following output if the setup was done correctly:
            /$$$$$$   /$$$$$$  /$$$$$$$
           /$$__  $$ /$$__  $$| $$__  $$
  /$$$$$$$| $$  \ $$| $$  \ $$| $$  \ $$ /$$$$$$   /$$$$$$
 /$$_____/| $$  | $$| $$  | $$| $$$$$$$//$$__  $$ /$$__  $$
| $$      | $$  | $$| $$  | $$| $$____/| $$$$$$$$| $$  \__/
| $$      | $$  | $$| $$  | $$| $$     | $$_____/| $$
|  $$$$$$$|  $$$$$$/|  $$$$$$/| $$     |  $$$$$$$| $$
 \_______/ \______/  \______/ |__/      \_______/|__/
=========================================================================
Hello I'm cOOPer! Nice to meet you!
=========================================================================
Log in or register to gain access to my features!
To log in, enter "login [yourUsername] /pw [password] /as [yourRole]".
To register, enter "register [yourUsername] /pw [password] /as [yourRole]".

To exit, enter "exit".
=========================================================================
>> [Logged out]
  1. Run JUnit tests (optional):
    1. Navigate to src/test.
    2. Right click on test and select ‘Run ‘All tests’ ‘.
    3. All the tests should pass, and you should see the following:

junitPassed

Before you code

  1. Configure coding style
    If you are using IntelliJ IDEA, follow this guide to set up IntelliJ to match our coding style.
  2. Set up Continuous Integration (CI)
    GitHub automatically detects the GitHub Actions config file located in the .github/workflows folder. CI for cOOPer is automatically run at each push to the ‘master’ branch or whenever a pull request is created.
  3. Get to know cOOPer’s design
    One last thing to know before you start coding is cOOPer’s overall software design. You are recommended to get some sense of cOOPer’s overall design in the Design section below.

⬆️ Back to top

Design

💡 The architecture diagram and UML diagrams in this document were created using draw.io. The .png templates used to create the diagrams can be found in the developerGuideDiagrams folder. To create and edit diagrams, access the draw.io website, select ‘Open Existing Diagram’ and open the desired .png file. Any changes to the diagram will be saved automatically.

Overview

cOOPer consists of two main layers: the verification layer and the features layer as shown in the diagram below. cOOPer recognizes different sets of inputs at each layer.

layerDiagram

Upon launching the app, the user starts at the verification layer where they can only log in or register. Entering valid credentials will then grant the user access to the features layer where they can input commands to use cOOPer’s features. At this layer, entering the logout command will bring the user back to the verification layer.

Architecture

architectureDiagram

The Architecture Diagram above shows the high-level design of cOOPer and how cOOPer’s components are connected.

Cooper contains the main method of the program. Cooper’s responsibilities are as such:

Apart from Cooper, the rest of the app consists of these seven components:

Interaction of the architecture components to process user input

ℹ️userInput represents the credentials input by the user for verification. For example, register John /pw 12345 /as admin.

signInSequenceDiagram

ℹ️ userInput represents a command input by the user. For example, meetings.
ℹ️XYZCommand is an object representing a command recognised by cOOPer. For example, MeetingsCommand.

commandSequenceDiagram

⬆️ Back to top

Ui Component

API: cooper.ui

uiComponent

The Ui component:

⬆️ Back to top

Parser Component

API: cooper.parser

parserComponent

The Parsercomponent:

⬆️ Back to top

Verification Component

API: cooper.verification

verificationComponent

The Verification component:

⬆️ Back to top

Command Component

API: Command.java

commandComponent

public class HelloCommand extends Command {
	// constructors and attributes for execution of the command are omitted
	public void execute() {
		System.out.println("Hello world!");
	}
}

The Command component:

⬆️ Back to top

Resources Component

API: cooper.resources

resourcesComponent

The Resources component:

Finance

API: cooper.finance

financeComponent

The Finance component:

Meetings

API: cooper.meetings

meetingsComponent

The Meetings component contains the MeetingManager and Meeting classes.

MeetingManager stores two attributes:

  1. the timings along with the usernames of the available users, which is a TreeMap<LocalTime, ArrayList<String>> object,
  2. the list of meetings scheduled, which is an ArrayList<Meeting> object.

The MeetingManager constructs the instances of Meeting, and stores it as an ArrayList<Meeting> in itself.

The Meetings component:

Forum

API: cooper.forum

forumComponent

The Forum component:

⬆️ Back to top

Storage Component

API: cooper.storage

storageComponent

ℹ️We do not put the StorageManager class under Resources for the following reasons:

  1. Storage class is cOOPer’s internal construct for bookkeeping various internal data structures and recovering them at startup. This does not categorise under any features the user can interact with and hence should not be kept under ResourcesManager.
  2. Storage has super privileges to access internal data structures of all components in Resources. This contradicts the goal of ResourcesManager which is to manage access rights to different features depending on user roles, and hence should be kept separate from it.

The Storage component:

⬆️ Back to top

Util Component

API: Util.java

⬆️ Back to top

Implementation

Parsing user input

cOOPer uses the dopsun chatbot-cli library as its frontend parser that allows you to define any arbitrary input schema under src/main/resources/parser/command-data.properties such as

login = login ${username-hint} /pw ${password-hint} /as ${role-hint}

The chatbot’s Parser library automatically parses the place-holders defined with $ leaders to strings. For example, login Yvonne /pw 12345 /as admin will be parsed into the following fields:

{ "username-hint" : Yvonne,
  "password-hint" : 12345,
  "role-hint" : admin }

This gives great flexibility and extensibility to the Parser component as you do not need to worry about writing new parsing schemes for every command and adding new commands to cOOPer for new features become trivial.

⬆️ Back to top

Verifying user credentials

The Verifier class facilitates the verification of the credentials of a user registering or logging in to cOOPer.

Verification process

Different conditions are checked depending on whether a user is trying to log in or register. For example, if a user is trying to register, cOOPer will check if the username is already registered and asks the user to log in if they are not registered yet. On the other hand, if an unregistered user is trying to log in, cOOPer will ask the user to register first.

For a registered user trying to log in, cOOPer will first check if the entered password is correct. This is done with the help of the PasswordHasher class which hashes the entered password with the user’s salt stored by cOOPer. The hash obtained will then be compared to the user’s stored hash to determine if the entered password is correct.

If the password is correct, the user’s role will then be checked to determine if they are logging in with the role they registered with.

Registering a user

The following sequence diagram shows the detailed process of registering a user.

ℹ️userInput is register John /pw 123 /as admin.
ℹ️The executeSignIn() method actually takes in a rawPassword as its parameters but is omitted in this sequence diagram as the registration process does not require the raw password of the user.

registrationSequenceDiagram

The SignInDetailsParser constructs a SignInDetails object parsed from the arguments in userInput. This SignInDetails object is then used to construct a Registration object which executes the registration of the user. This process is shown by the sequence diagram below.

refFrameSequenceDiagram

Logging in

Assuming that the above registration has taken place successfully, the following sequence diagram shows the login process of the user.

ℹ️userInput is login John /pw 123 /as admin.
ℹ️The process of parsing userInput takes place similar to when a user is registering. The reference frame is omitted in this sequence diagram for simplicity.

loginSequenceDiagram

Hashing user passwords

The Password Based Key Derivation Function (PBKDF2) hashing algorithm is used for hashing user passwords. This algorithm is used together with a 64-bit salt text for each password before it is hashed to improve security and decrease susceptibility to rainbow-table attacks, where duplicate user passwords are still stored securely.

This algorithm is recommended by the National Institute of Standards and Technology (NIST) for password storage and our implementation also adheres to NIST specifications:

⬆️ Back to top

Requesting a resource

The Resources component manages the access rights to other manager components like the FinanceManager, MeetingManager and ForumManager. The following sequence diagram shows the two main operations of ResourcesManager:

resourcesSequenceDiagram

⬆️ Back to top

Interacting with finance functions

The Finance component provides features such as adding and listing of financial statements, i.e. the balance sheet and cash flow statement as well as compounded projection of Free Cash Flow growth.

Adding to the financial statement

The sequence diagram below illustrates the process of adding to a given financial statement, in this case the balance sheet.

financeSequenceDiagram

When the user wants to add an entry to a financial statement, FinanceManager will first determine if the amount should reflect as positive or negative in the financial statement, as well as which section of the financial statement the entry belongs to. FinanceManager will then add the entry to the respective financial statement and its section’s net amount.

Viewing the financial statement

When the user wants to view a financial statement with list, FinanceManager will run a check that the net amounts of each section of the financial statement are calculated correctly before the statement is displayed to the output.

Projecting cash flow

When the user wants to project free cash flow, FinanceManager will first help to calculate free cash flow by subtracting the CapEx (Capital Expenditure: a field of the cash flow statement) from the total cash from Operating Activities. Subsequently FinanceManager will compare this value to the previous year’s value, and calculate the percentage increase. This percentage increase will then be used in a recursive periodic compound interest formula to calculate the following year’s free cash flow, at the same percentage increase.

⬆️ Back to top

Generating a PDF from the financial statement

The PdfGenerator abstract class is responsible for the generation of the financial statement as a PDF via the generate command. It is inherited by the subclasses, BalanceSheetGenerator and CashFlowStatementGenerator, with each subclass containing different methods to add different sections to the PDF.

Creating the PDF with LaTeX

The PDF is generated with the help of an online LaTeX compiler. The LaTeX (.tex) templates for the PDF can be found under src/main/resources/pdf. The PdfGenerator class employs the use of the inputStreamToString() method of the Util component to convert the contents of these LaTeX templates into a String object. The LaTeX template, which is now a String is then manipulated by calling Java String methods like replace() and append(). Certain identifiers (in the form of LaTeX comments ‘%’) in the LaTeX template will be replaced by the actual values of cOOPer’s financial statement.

The example below shows the template of an entry in the financial statement:

\centering
% {Description}
& \centering
& \centering
& \centering
& % {Amount}
\\[3ex]

Calling replace("% {Description}", "Depreciation and Amortisation") and replace("% {Amount}", 1500) on the template above will result in the following:

\centering
Depreciation and Amortisation
& \centering
& \centering
& \centering
& 1500
\\[3ex]

When compiled, the LaTeX code above will correspond to an entry ‘Depreciation and Amortisation’ on the PDF with the amount $1500. This technique can be used on the header and summary templates which will format the header and summary of a particular section in the financial statement.

The methods createHeader(), createEntry() and createSummary() in PdfGenerator perform the text replacement as shown above. The diagram below shows how these methods correspond to the different parts of the ‘Operating Activities’ section in the cash flow statement PDF.

pdfSections

Compiling the LaTeX code online

createHeader(), createEntry() and createSummary() also add the template to an ArrayList after performing the text replacement on the template. Iterating through the ArrayList, these templates are then appended together using append(). This forms a long String which is then sent to the online LaTeX compiler via a POST request. The reply data obtained from the request is used to construct the PDF via the write() method of Java’s FileOutputStream class.

⬆️ Back to top

Declaring an availability

The MeetingManager class facilitates the storing of availability in cOOPer.

Availability declaration process

When the user declares an availability, the addAvailability function in MeetingManager performs some checks before successfully storing their availability.

  1. addAvailability looks at the format of the [date] and [time] entered, which will be checked using the isValidDateTimeFormat function.
  2. addAvailability checks if the time entered is at the start of the hour, using the isStartOfHour function.
  3. addAvailability checks if the user has already entered their availability under the same date and time, by checking all the names under the specified date and time in the availability TreeMap.

The following sequence diagram shows the detailed process of declaring an availability. username is Sebastian and userInput is available 11-08-2021 14:00.

availableSequenceDiagram

⬆️ Back to top

Scheduling a meeting

The MeetingManager class facilitates the scheduling of meetings.

Scheduling process

When the user schedules a meeting ScheduleCommand checks if the [date] and [time] parameter is entered and calls manualScheduleMeeting in MeetingManager if it is and autoScheduleMeeting if it isn’t.

The following sequence diagram shows the process of automatically scheduling a meeting. username of the user scheduling is Sebastian and userInput is schedule Project Meeting /with Eugene.

autoScheduleSequenceDiagram

The following sequence diagram shows the process of manually scheduling a meeting. username of the user scheduling is Sebastian and userInput is schedule Project Meeting /with Eugene /at 11-08-2021 14:00.

manualScheduleSequenceDiagram

⬆️ Back to top

Interacting with the forum

The following sequence diagram shows three operations with the forum, addPost, commentPost and deletePost.

forumSequenceDiagram

⬆️ Back to top

Saving and loading data

ℹ️Due to the way the Storage component is implemented, the classes and methods used for storage have names which are quite similar. In order to generalize the explanations in this section for how data is saved and loaded, the term XYZ will be used as a placeholder where XYZ is signInDetails, balanceSheet, cashFlowStatement, availability, meetings and forum.

The StorageManager class facilitates the saving and loading of cOOPer’s data to and from its storage files. This data includes the sign in details of registered users (from the Verification component) , entries of the balance sheet and cash flow statement, list of availabilities, scheduled meetings, and forum posts (all from the Resources component). cOOPer’s data is stored separately in multiple text files named XYZ.txt located in the ‘cooperData’ folder in the home folder.

Saving data

Certain commands, when executed successfully, can change the data in the Verification and Resources components. (e.g. register, add, available, etc.) Whenever the data in these components change, the command that made the change will call the saveXYZ() method of the StorageManager to update the storage file with the change. For example, when a new availability is added successfully, the method saveAvailability() is called by AvailableCommand and the storage file is updated with the new list of availabilities.

The following sequence diagram shows the general procedure of saving data to the storage file whenever a change is made.

saveDataSequenceDiagram

Loading data

Data is loaded from cOOPer’s storage files into the Verification and Resources component upon launching the app. The StorageManager constructor is first called and each subclass XYZStorage is initialized with the file paths of their storage files, XYZ.txt. The loadAllData() method of StorageManager is then called and this method in turn calls the loadXYZ() methods of the XYZStorage subclasses. If the storage files are not present upon launching cOOPer, the storage files will be created and any error in file creation will be made known to the user. Since data in the storage files are of a specific format, any change to the storage format will throw an InvalidFileDataException and a message will be printed to specify the file containing invalid data.

The following sequence diagram shows the general procedure of loading data from the storage file upon launching cOOPer.

loadDataSequenceDiagram

Storage design considerations

Current choice: Individual subclasses which store the sign in details of registered users, entries of the balance sheet and cash flow statement, list of availabilities, scheduled meetings, and forum posts in separate storage files.

⬆️ Back to top

Appendix: Requirements

Product scope

Target user profile

The target user profile of cOOPer consists of all levels of administration in a tech startup, namely from the employee level of Secretary up to the management level of CEO.

Example Users:

Value proposition

cOOper’s value proposition: Manage company financials faster than typical human accounting means & manage company communication more reliably than a typical GUI driven app.

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 ‘help’ instructions refer to them when I forget how to use the application
*** new user register an account login and return to my saved work at any point later on
*** user see a list of roles at login login to the specific role I need to carry out a task
*** user have a password encrypted login have my saved work be protected from any external tampering
*** finance admin create the company’s financial statements assess the company’s current financial health accurately and quickly
*** secretary employee see all company personnel’s daily availability schedule meetings between all available members easily
** finance admin automatically generate projections on the company’s yearly profitability assess the company’s potential future growth
** finance admin generate the company’s financial statements as a PDF document view and share a neat version of the financial statement with my colleagues
** employee make posts on a company forum discuss difficulties or interesting developments in the company
** employee add my available timings for meetings ease the scheduling of meetings with my colleagues
** secretary employee automatically schedule a meeting without having to know other person’s availability save time on finding an appropriate time to meet
* user in a hurry customise shortcut keys in the app save time on retrieving the data I desire

Non-Functional Requirements

⬆️ Back to top

Glossary

⬆️ Back to top

Appendix: Instructions for Manual Testing

Launch and shutdown

  1. Launching cOOPer
    1. Download cOOPer’s latest JAR file here and copy the JAR file into an empty folder.
    2. Launch the Command Prompt / Terminal from the folder.
    3. Check the Java version being used by entering java -version. Ensure that you are using Java 11 or above.
    4. Run java -jar cOOPer.jar.
      Expected output: cOOPer’s greeting message is shown.
  2. Exiting cOOPer
    1. Enter exit.
      Expected output: cOOPer’s bye message is shown and the program exits successfully.

Sign-in

  1. Registering
    1. Ensure that the label beside cOOPer’s command prompt shows [Logged out].
    2. Enter register [username] /pw [password] /as [role] where [username] is your username, [password] is your password and [role] is one of ‘admin’ or ‘employee’.
      Expected output: A message informing you that you have successfully registered is shown.
  2. Logging in
    1. Ensure that the label beside cOOPer’s command prompt shows [Logged out].
    2. Enter login [username], /pw [password] /as [role] where [username], [password] and [role] are the username, password and role you registered with.
      Expected output: A message informing you that you are now successfully logged in is shown. The [Logged out] label at the command prompt is no longer present.

Viewing help

  1. Viewing help
    1. Ensure that you are logged in to cOOPer.
    2. Enter help.
      Expected output: A list of commands specific to your role is shown along with their formats.

Finance actions

  1. Creating the balance sheet
    1. Ensure that you are logged in as an admin.
    2. Enter bs to initiate the balance sheet function.
    3. Ensure that the label beside the command prompt shows [Balance Sheet].
    4. Enter add [amount] to add the first entry.
      Expected output: You will be prompted by cOOPer for the next entry.
    5. Repeat step iv until cOOPer prompts you to enter list upon completion of the balance sheet.
  2. Viewing the balance sheet
    1. Ensure that you are logged in as an admin.
    2. Enter bs to initiate the balance sheet function.
    3. Ensure that the label beside the command prompt shows [Balance Sheet].
    4. Enter list to view the current balance sheet.
      Expected output: All entries will be displayed with the respective net amounts, as well as a check for if the sheet balances.
  3. Creating the cash flow statement
    1. Ensure that you are logged in as an admin.
    2. Enter cf to initiate the cash flow statement function.
    3. Ensure that the label beside the command prompt shows [Cash Flow].
    4. Enter add [amount] to add the first entry.
      Expected output: You will be prompted by cOOPer for the next entry.
    5. Repeat step iv until cOOPer prompts you to enter list upon completion of the cash flow statement.
  4. Viewing the cash flow statement
    1. Ensure that you are logged in as an admin.
    2. Enter cf to initiate the cash flow statement function.
    3. Ensure that the label beside the command prompt shows [Cash Flow].
    4. Enter list to view the current cash flow statement.
      Expected output: All entries will be displayed with the respective net amounts.
  5. Generating cash flow projections
    1. Ensure that you are logged in as an admin.
    2. Ensure all the fields of the cash flow statement have been filled using cfadd.
    3. Enter proj [years] to project up to your specified number of years.
      Expected output: All the projected values of free cash flow will be displayed up to the specified year.

Generating the PDF

The generate command works regardless of whether the prompt label is showing [Balance Sheet], [Cash Flow] or is not even present.

  1. Generating the balance sheet
    1. Ensure that you are logged in as an admin.
    2. Fill up the balance sheet with bsadd.
    3. Ensure that you have an active Internet connection.
    4. Enter generate bs.
      Expected output: A message informing you that the PDF has been successfully generated is shown. A PDF named ‘BalanceSheet.pdf’ is created in a folder named ‘output’ in the folder containing the JAR file.
  2. Generating the cash flow statement
    1. Ensure that you are logged in as an admin.
    2. Fill up the cash flow statement with cfadd.
    3. Ensure that you have an active Internet connection.
    4. Enter generate cf.
      Expected output: A message informing you that the PDF has been successfully generated is shown. A PDF named ‘CashFlowStatement.pdf’ is created in a folder named ‘output’ in the folder containing the JAR file.

Meetings actions

  1. Declaring availability
    1. Ensure that you are logged in to cOOPer.
    2. Enter available [date in dd-MM-yyyy] [time in HH:mm].
      Expected output: A confirmation informing you that your username has been added to the date and time is shown.
  2. Viewing availability
    1. Ensure that you are logged in to cOOPer.
    2. Enter availability.
      Expected output: A table with the availability of all users is shown.
  3. Scheduling meeting
    1. Ensure that you are logged in to cOOPer.
    2. Ensure that you and one or more users have entered their availability at a common date and time.
    3. Enter schedule [meetingName] /with [username]. [username] is a user(not you) who is available in at least one common date and time as you.
    4. Alternatively, you can also enter schedule [meetingName] /with [username] /at [date] [time]. [username] and yourself must be both available at this date and time.
      Expected output: A confirmation message informing you that the meeting is successfully scheduled is shown.
  4. Viewing meetings
    1. Ensure that you are logged in to cOOPer.
    2. Enter meetings.
      Expected output: A table with all your meetings, their date and time, and their attendees is shown.

Forum actions

  1. Adding a post
    1. Ensure that you are logged in to cOOPer.
    2. Enter post add hello world.
      Expected output: A box with the post you just added is shown as confirmation.
  2. Commenting on a post
    1. Ensure that you are logged in to cOOPer.
    2. Ensure you have added at least one post.
    3. Enter post comment hello world 2 /on 1.
      Expected output: A box with the post and your comment you just entered is shown as confirmation.
  3. Deleting a post
    1. Ensure that you are logged in to cOOPer.
    2. Ensure you have added at least one post.
    3. Enter post delete 1.
      Expected output: A box with the post you just deleted is shown as confirmation.
  4. Listing all posts
    1. Ensure that you are logged in to cOOPer.
    2. Ensure you have added at least one post.
    3. Enter post list all.
      Expected output: A box containing all posts and comments you have entered so far is shown.

Logging out

  1. Logging out
    1. Ensure that you are logged in to cOOPer.
    2. Enter logout. Expected output: A message informing you that you have logged out of cOOPer is shown along with the instructions on how to log in, register or exit. The label at the command prompt now shows [Logged out].

⬆️ Back to top