PROJECT: MeNUS


This portfolio aims to provide a summary of my contribution as Team Lead for the project, MeNUS.

Overview

MeNUS is a restaurant management desktop application targeting restaurant owners in the National University of Singapore (NUS). It is built to help them better manage core aspects of their restaurants  —  accounts (i.e. employees), menus, ingredients, sales and reservations management — all within a single application!

Restaurant owners interact with MeNUS using a Command Line Interface (CLI). MeNUS also has a Graphical User Interface(GUI) created with JavaFX and it is written using Java 9 with approximately 30 KLoC.

It is cross-platform supported and can be used on both Windows-based and Unix-based platforms.

Summary of Contributions

  • Code contributed: RepoSense

  • Major enhancement: Added the accounts management feature

    • What it does: Allows the restaurant owner to create an account for each of his employee to manage the system on his behalf.

    • Justification: This feature implements a security layer by ensuring that only authorised employees are able to execute commands based on their level of privilege. In addition, it provides accountability as executed commands can be traced back to the respective user.

    • Highlights: This enhancement affects existing commands as certain commands will only be executed if the user is authorised to do so. It required an in-depth analysis and understanding of the Logic,Model and Storage components. Also, the implementation was challenging as it required modifications to existing commands.

    • Credits: Passwords are secured using bcrypt.

  • Other contributions:

    • Minor enhancements:

      • Added side navigation bar to allow access to the different components of the application with a click of a mouse or trackpad, in addition to doing so via the CLI.

      • Morphed the code base into a different product.

    • Project management:

      • Team Lead; responsible for overall project coordination.

      • Set up and configured GitHub repository, Travis, AppVeyor, Codacy, Coveralls, Netlify, RepoSense and Discord automatic notifications using Webhook.

      • Maintained issue tracker, milestone, project board and merging of pull requests (PRs).

      • Managed releases v1.1, v1.2, v1.2.1, v1.3, v1.3.1, v1.4 (6 releases) on GitHub.

    • Documentation:

      • Restructured project website to resemble an actual product.

      • Added introductions to User Guide and Developer Guide to make them more reader-focused.

      • Added Using Git with Sourcetree section to the Developer Guide.

      • Added instructions for manual testing for Accounts Management.

      • Morphed the existing contents of the User Guide and Developer Guide with respect to the morphed code base.

    • Community:

    • Tools:

      • Integrated a third party library (bcrypt) to the project: #38, #70

    • Miscellaneous:

      • Practiced good PR hygiene by ensuring no loss of code coverage.

      • Chaired weekly face-to-face meeting.

Contributions to the User Guide

The following sections are my contribution to the User Guide. They showcase my ability to write documentation targeting end-users with little or no technical knowledge.

Welcome to MeNUS

MeNUS empowers you to improve the management and its efficiency of your restaurants in NUS.

As long as you feel that you are using too many complex and expensive systems to manage your restaurants, MeNUS is here to help you and it is the only restaurant management system you will ever need.

Introducing MeNUS, a revolutionary restaurant management desktop application that is optimized for users who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, MeNUS allows you to manage core aspects of your restaurants — accounts (i.e. employees), menus, ingredients, sales and reservations management — all within a single application!

Legend

The following 3 callouts will be used throughout the documentation which you may wish to pay attention to as it may contain important details:

Just for your info, do not be alarmed. Be sure to read these notes as it might contain some important information.
Perhaps something can be done using another approach, but it is up to you to decide. Tips are often not important and can be safely ignored.
Some things might go wrong if you are not careful, or did not follow the instructions correctly. You are strongly advised to read whatever is in this block.

A Quick Look at MeNUS

MeNUS’s user interface is split into a few sections. These sections are highlighted in the image below.

UserInterfaceHighlight

Let’s get started!

Accounts Management

Logging in: login

Logs into an existing account.
Format: login id/USERNAME pw/PASSWORD

Examples:

  • login id/root pw/1122qq

To testers: You may access the application using the default root account: login id/root pw/1122qq

Logging out: logout

Logs out of the account.
Format: logout

History will automatically be cleared upon logging out

Creating user account: register or reg

Creates a new user account.
Format: register id/USERNAME pw/PASSWORD n/FULL_NAME or reg id/USERNAME pw/PASSWORD n/FULL_NAME

This command will be improved in the future to support user role (i.e. privilege system). See Section 5.7.1, “Improving registration [coming in v2.0]” for more information

Examples:

  • register id/azhikai pw/1122qq n/Ang Zhi Kai

  • reg id/azhikai pw/1122qq n/Ang Zhi Kai

Changing user password: change-password or cp

Edits the password of the current logged in user account.
Format: change-password npw/NEW_PASSWORD or cp npw/NEW_PASSWORD

Examples:

  • change-password npw/1122qq

  • cp npw/1122qq

Deleting user account: deregister or dereg

Deletes an existing user account.
Format: deregister id/USERNAME or dereg id/USERNAME

This command will only be executable by a highly privileged user in the future. See Section 5.7.2, “Creating user role [coming in v2.0]” for more information

Examples:

  • deregister id/azhikai

  • dereg id/azhikai

Select user account: select-account or sa

Selects the account identified by the index number.
Format: select-account INDEX or sa INDEX

  • The index refers to the index number shown in the displayed item list

  • The index must be a positive integer 1, 2, 3, …​

Selecting the account does not render any data on the detailed panel due to the simplicity of the data itself

Examples:

  • list-accounts
    select-account 2
    Selects the 2nd account in the list.

  • fa azhikai
    sa 1
    Selects the 1st account in the results of the find-account command.

Locating account by username: find-account or fa

Finds account whose username contains the keyword.
Format: find-account KEYWORD or fa KEYWORD

  • The search is case insensitive. e.g Root will match root

  • Only the username is searched

  • Only one keyword is allowed since username does not contain spaces

  • Full keyword is not necessary; e.g. roo and root will match root

Examples:

  • find-account root or fa root
    Return any accounts whose username contains the string root

List user accounts: list-accounts or la

List all user accounts.
Format: list-accounts or la

Passwords are not and should not be displayed

Contributions to the Developer Guide

The following sections are my contribution to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Welcome to MeNUS

This Developer Guide is written by the MeNUS v1.4 team for the benefits of future developers and maintainers of the application.

  • This guide includes instructions for setting up the development environment.

  • This guide provides sufficient UMLs (unified model diagrams) to illustrate the architectural structure and design methodology.

  • This guide offers advice for troubleshooting some common issues.

MeNUS is an open-source project. If you are interested in contributing, see the Contact Us page for more information.

Legend

The following 3 callouts will be used throughout the documentation which you may wish to pay attention to as it may contain important details:

Just for your info, do not be alarmed. Be sure to read these notes as it might contain some important information.
Perhaps something can be done using another approach, but it is up to you to decide. Tips are often not important and can be safely ignored.
Some things might go wrong if you are not careful, or did not follow the instructions correctly. You are strongly advised to read whatever is in this block.

User account feature

Current Implementation

The user account mechanism is facilitated by RestaurantBook. Additionally, it implements the following operations:

  • RestaurantBook#getAccount(Account) — Retrieves the account.

  • RestaurantBook#addAccount(Account) — Saves the new account.

  • RestaurantBook#updateAccount(Account, Account) — Update the existing account.

  • RestaurantBook#removeAccount(Account) — Removes the account.

These operations are exposed in the Model interface as Model#getAccount(Account), Model#addAccount(Account), Model#updateAccount(Account, Account) and Model#removeAccount(Account). The following commands will invoke the aforementioned operations:

  • Command#LoginCommand() — Invokes Model#getAccount(Account).

  • Command#RegisterCommand() — Invokes Model#addAccount(Account).

  • Command#DeregisterCommand() — Invokes Model#removeAccount(Account).

  • Command#ChangePasswordCommand() — Invokes Model#updateAccount(Account, Account).

Given below are example usage scenarios and how each of the command and its respective operations behave at each step which involves two components, Logic which is responsible for parsing the user input and Model which is responsible for manipulating the list, if necessary. Both components are extended by LogicManager and ModelManager respectively.

The following sequence diagram shows how the register command works:

RegisterSequenceDiagram

Figure 4.2.1.1: Sequence diagram to illustrate component interactions for the register command

  • We assume the user is already logged in to an account with appropriate privilege level (e.g. Administrator)

  • If the username already exists, a warning message will be shown to the user to select another username

  • The deregister command works the same way by checking if the account exists before calling Model#removeAccount(Account)

Step 1. The user executes register id/azhikai pw/1122qq n/Ang Zhi Kai command to create a new user account.

Step 2. LogicManager invokes the RestaurantBookParser#parseCommand() method which takes in the user input as arguments.

Step 3. When the command is parsed, the Command#RegisterCommand() will be created which is returned to the LogicManager.

Step 4. LogicManager invokes the execute() method of the Command#RegisterCommand(), rc which is instantiated in Step 3. The Model component will be involved as the Command#RegisterCommand() invokes a request to add the account into the storage by calling Model#addAccount(Account).

Step 5: The new account is added into the storage. Then, a CommandResult is generated and returned to LogicManager which is used to display the result to the user.

The following sequence diagram shows how the login command works:

LoginSequenceDiagram

Figure 4.2.1.2: Sequence diagram to illustrate component interactions for the login command

We assume the user will enter the correct password. Otherwise, warning message will be shown to the user to re-enter the credential

Step 1. The user executes login id/azhikai pw/1122qq command to login to an existing user account.

Step 2. LogicManager invokes the RestaurantBookParser#parseCommand() method which takes in the user input as arguments.

Step 3. When the command is parsed, the Command#LoginCommand() will be created which is returned to the LogicManager.

Step 4. LogicManager invokes the execute() method of the Command#LoginCommand(), lc which is instantiated in Step 3. The Model component will be involved as the Command#LoginCommand() invokes a request to retrieve an account based on the username. If it exists, the account will be retrieved and the password hash will be compared. If it matches, then the credential is valid and the user is authenticated.

The following activity diagrams summarize how password is processed during the login and registration process:

PasswordLoginActivityDiagram

Figure 4.2.1.3: Activity diagram to illustrate how password is processed for the login command

PasswordHashActivityDiagram

Figure 4.2.1.4: Activity diagram to illustrate how password is processed for the register command

Design Considerations

Aspect: How password is secured
  • Alternative 1 (current choice): Use username to generate cryptographic salt.

    • Rationale: If we allow the bcrypt library to generate the salt, testing ability will be limited as the salt is generated based on system time by default. This means that despite testing the same account with the same raw password, its equality will never match. Hence, a workaround is to generate the salt based on its username which is unique to each account.

    • Pros: Easy to implement and improves testing ability.

    • Cons: If an attacker knows how the salt is generated, it could pose a security risk.

  • Alternative 2: Use salt generated by the bcrypt library with high cost factor.

    • Pros: Higher cost factor makes hashing of the password harder. Ideally, the cost factor should as high as the system can tolerate, given the other tasks the system must otherwise fulfill.

    • Cons: More processing resources used and existing test cases must be updated.

User session feature

Current Implementation

If a privileged command is executed when a session is not set, an error will be shown. For more information on which commands are guest-executable, see the UserGuide.adoc for more information

The application’s user session state is facilitated by UserSession. This is triggered by raising a Login or Logout event upon executing the Command#LoginCommand() or Command#LogoutCommand() respectively.

Additionally, it implements the following static operations:

  • UserSession#create(Account) — Set a user session.

  • UserSession#destroy() — Removes the existing user session.

  • UserSession#update(Account) — Updates the existing user session.

  • UserSession#isAuthenticated() — Checks if there is an existing login session.

The following activity diagram summarizes how the user session is modified when a user logs in or out:

UserSessionActivityDiagram

Figure 4.3.1.1: Activity diagram to illustrate the user session

The following code snippet demonstrates how these static methods are implemented:

/**
 * Stores this {@link Account} info as part of this session.
 *
 * @param account logged in for this session.
 */
public static void create(Account acc) {
    if (!isAuthenticated) {
        isAuthenticated = true;
        account = acc;
    }
}

/**
 * Logs out of this account which releases this session.
 */
public static void destroy() {
        isAuthenticated = false;
        account = null;
}

/**
 * Updates the session with the new account info, such as updating of account password.
 *
 * @param acc that has been updated.
 */
public static void update(Account acc) {
    if (isAuthenticated) {
        account = acc;
    }
}

Design Considerations

Aspect: How user session is handled
  • Alternative 1 (current choice): Use static flags and methods.

    • Pros: Easy to implement, given the constraints.

    • Cons: Can only support one user at any time. If another user wants to login, the current logged in user must log out. In addition, since it is a global class object, test cases may be affected when testing both guest and privileged commands which requires user to be logged out and logged in respectively.

  • Alternative 2: Store a list of user sessions to allow multiple login.

    • Pros: More user can login and manage the systems concurrently. Potentially able to resolve the global dependency of the current solution which might affect the test ability.

    • Cons: More memory usage to track each user session as the application scales with more users.