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
andStorage
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:
-
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.
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 |
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
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 thefind-account
command.
Locating account by username: find-account
or fa
Finds account whose username contains the keyword.
Format: find-account KEYWORD
or fa KEYWORD
Examples:
-
find-account root
orfa root
Return any accounts whose username contains the stringroot
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()
— InvokesModel#getAccount(Account)
. -
Command#RegisterCommand()
— InvokesModel#addAccount(Account)
. -
Command#DeregisterCommand()
— InvokesModel#removeAccount(Account)
. -
Command#ChangePasswordCommand()
— InvokesModel#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:
Figure 4.2.1.1: Sequence diagram to illustrate component interactions for the register
command
|
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:
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:
Figure 4.2.1.3: Activity diagram to illustrate how password is processed for the login
command
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:
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.
-