Refer to the guide Setting up and getting started.
The architecture diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main (consisting of classes Main and MainApp) is in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI: The UI of the App.Logic: The command executor.Model: Holds the data of the App in memory.Storage: Reads data from, and writes data to, the hard disk.Commons represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The sequence diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.
Each of the four main components (also shown in the diagram above),
interface with the same name as the Component.{Component Name}Manager class (which follows the corresponding API interface mentioned in the previous point.For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter etc. All these, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
The UI component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
The UI component,
Logic component.Model data so that the UI can be updated with the modified data.Logic component, because the UI relies on the Logic to execute commands.Model component, as it displays Person object residing in the Model.API : Logic.java
Here's a (partial) class diagram of the Logic component:
The sequence diagram below illustrates the interactions within the Logic component, taking execute("delete 1") API call as an example.
Note: The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the Logic component works:
Logic is called upon to execute a command, it is passed to an AddressBookParser object which in turn creates a parser that matches the command (e.g., DeleteCommandParser) and uses it to parse the command.Command object (more precisely, an object of one of its subclasses e.g., DeleteCommand) which is executed by the LogicManager.Model when it is executed (e.g. to delete a person).Model) to achieve.CommandResult object which is returned back from Logic.Here are the other classes in Logic (omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AddressBookParser class creates an XYZCommandParser (XYZ is a placeholder for the specific command name e.g., AddCommandParser) which uses the other classes shown above to parse the user command and create a XYZCommand object (e.g., AddCommand) which the AddressBookParser returns back as a Command object.XYZCommandParser classes (e.g., AddCommandParser, DeleteCommandParser, ...) inherit from the Parser interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model component,
Person and Reservation objects (which are contained in the
UniquePersonList and UniqueReservationList objects respectively.
UniquePersonList objects: one called persons representing the contacts list and another called archivedPersons for the archived list.Person objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Person> 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.Reservation objects in the same fashion as 'selected' Person objects.UserPref object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref objects.Model represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a Tag list in the AddressBook, which Person references. This allows AddressBook to only require one Tag object per unique tag, instead of each Person needing their own Tag objects.
API : Storage.java
The Storage component,
AddressBookStorage and UserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed).Model component (because the Storage component's job is to save/retrieve objects that belong to the Model)Classes used by multiple components are in the seedu.addressbook.commons package.
This section describes some noteworthy details on how certain features are implemented.
The implementation of help command is more related to the Ui part of the code compared to other commands as it opens another window to show the command summary. It is facilitated by the handleHelp method in the MainWindow class.
The following activity diagram shows how a user views the help window with the help command.
Given below is an example usage scenario of the help command.
Step 1. The user launches the application. The user will see the main window of the address book.
Step 2. The user executes the help command to open the help window. The MainWindow#executeCommand() will call MainWindow#isShowHelp() to check if the command to be executed is a help command. The help command is detected and causes Model#handleHelp() to be called which opens the help window.
Step 3. The user looks through the command summary table to find the information needed.
Step 4. The user can copy the website address by clicking Copy URL button in the help window and navigate to the website for more detailed information.
Note The user can do this anytime as long as the help window is opened.
Step 5. The user can then click the X on top right corner or pressQ on keyboard to close the help window.
Aspect: How help window is presented:
Option 1 (current choice): The website address and things to note on top of a command summary table.
Option 2: Only the website address.
The filtering of contacts by tag is facilitated by HasMatchingTagPredicate. It implements the Predicate<Person> interface and overrides the test(Person) method, which is used to decide which Persons will be displayed after the filter command. The test(Person) method will return true only if the person has a tag matching every filter tag.
Here is the class diagram for FilterCommand.
The following sequence diagram shows how a filter command goes through the Logic component.
Note: The lifeline for FilterCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
To safeguard against accidentally clearing the contacts list, the clear command requires the user to input a confirmation after the initial clear command. This is performed with the use of the two flags in the ModelManager class, namely isAwaitingClear and isConfirmClear, where their statuses are checked within the execution of the clear command since the model is passed to the command.
Another flag, previouslyClear, is used in the LogicManager class to check if the previous command was a clear command before handling the current command entered, where it checks if a confirmation "y" is entered.
The following activity diagram summarizes what happens when a user executes a clear command:
The archive command essentially removes the person from the UniquePersonList persons and places the person into the UniquePersonList archivedPersons in the address book, hiding the person's contact from the main list.
In this example, Irfan was initially in the persons list, at INDEX 1.
After being archived, Irfan was removed from the persons list and added to the archivedPersons list.
The archive command has its corresponding unarchive command which conversely removes the person from the archivedPersons list and adds them into the persons list inside the address book.
There is also the associated alist command that displays all the contacts that have been added into the archivedPersons list.
Archiving in CulinaryContacts has also been implemented in a way that allows for all other commands to be performed on the archived list. This was achieved by modifying the FilteredList<Person> filteredPersons within the ModelManager class to dynamically contain either the archived persons or the normal persons. This is because many of the original commands already make use of the filteredPersons list to execute the commands on. For commands that do not use the filteredPersons list in their execution, the flag isViewingArchivedList within the ModelManager is used instead in order to check if the user is currently viewing the normal persons or the archived persons before performing the command on the corresponding list.
Target user profile:
Value proposition: This app offers streamlined contact and reservation management for small family-owned restaurants, enhancing operational efficiency without covering financial or inventory aspects. It also categorises and stores detailed information about suppliers and the food that they sell to help owners keep track of volatile contacts.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * | new user | view the user guide easily | learn more about the app as and when I need |
* * * | new user | use a command to exit the program | close the application without moving my mouse |
* * * | new user | add new contacts | save their contact details |
* * * | new user | tag new contacts as 'supplier', 'customer' or 'employees' | keep my contacts list organized |
* * * | new user | view all the contacts that I currently have in my address book | |
* * * | new user | delete existing contacts | remove any unwanted or experimental contacts |
* * * | new user | find specific contact(s) by name | |
* * * | new user | add new reservations | |
* * * | new user | delete existing reservations | |
* * * | new user | archive contacts of employees/suppliers whose contracts have expired | declutter my contacts list |
* * * | new user | unarchive contacts | contact them when the need arises |
* * * | intermediate user | edit existing contacts | update contacts easily without deleting and recreating a new one |
* * * | intermediate user | filter my contacts by specific tag(s) | |
* * * | clumsy user | get a confirmation message when clearing the entire address book | avoid accidentally deleting all contacts |
* * | new user | see a helpful message when my command is not formatted correctly | figure out how to fix my command |
* * | new user | try out the features with some sample data | understand what each feature does |
* * | new user | tag suppliers with the types of food they supply | easily find the right supplier for specific ingredients |
* * | new user | tag employees as 'full time' or 'part time' | easily find the contacts of part time employees during peak period |
* * | forgetful user | see all commands I entered this session | |
* * | clumsy user | undo my last command | so that I can rectify an erroneous command |
* * | user with poor eyesight | view the contact details in a larger window when I click on a contact | more easily see the contact details |
* * | user with poor eyesight | have tags with different colors | easily differentiate tags |
* * | intermediate user | sort reservations by date and time | plan the seating arrangement and kitchen workload effectively |
* * | intermediate user | toggle between previous commands by pressing up and down arrows | save time typing similar commands |
* * | intermediate user | delete multiple contacts in 1 command | remove multiple contacts more quickly |
* * | intermediate user | see upcoming reservations/events in a dashboard | anticipate and prepare for such events |
* * | intermediate user | add special requests (e.g. dietary restrictions) to reservations | provide personalized service to my customers |
* * | expert user | create my own aliases and shortcuts | reduce time spent typing commands |
* | clumsy user | find contacts that match the keyword partially | avoid retyping the command when I make a typo |
* | intermediate user | import contacts from other sources | quickly populate the app with existing information |
* | intermediate user | have autocomplete when typing commands | finish typing the command faster |
* | intermediate user | automatically create a blank email addressed to a contact when I click on his/her email field | email contacts more quickly |
* | expert user | access the app from multiple devices | manage my contacts and reservations on the go |
(For all use cases below, the System is CulinaryContacts and the Actor is the user, unless specified otherwise)
Use case: UC01 - View help
MSS
User requests to see the help menu.
CulinaryContacts opens up the help window, displaying the command summary.
Use case ends.
Use case: UC02 - Add a person
MSS
User requests to add a new person.
CulinaryContacts adds the new person to the displayed person list.
Use case ends.
Extensions
1a. The provided field(s) is/are invalid.
1a1. CulinaryContacts shows an error message.
Use case resumes from step 1.
1b. Compulsory field(s) is/are missing.
1b1. CulinaryContacts shows an error message.
Use case resumes from step 1.
Use case: UC03 - List all persons in contacts list
MSS
User requests to show all persons in the contacts list.
CulinaryContacts shows all persons in the contacts list.
Use case ends.
Use case: UC04 - Edit a person
MSS
User requests to list all persons in the contacts list (UC03) or list all persons in the archived list (UC09).
User requests to edit the fields of a specific person in the displayed person list.
CulinaryContacts edits the fields of the person.
Use case ends.
Extensions
1a. The list is empty.
Use case ends.
2a. The given index is invalid.
2a1. CulinaryContacts shows an error message.
Use case resumes from step 2.
2b. The new field value(s) is/are invalid.
2b1. CulinaryContacts shows an error message.
Use case resumes from step 2.
2c. No fields to edit are provided.
2c1. CulinaryContacts shows an error message.
Use case resumes from step 2.
Use case: UC05 - Find a person
MSS
User requests to list all persons in the contacts list (UC03) or list all persons in the archived list (UC09).
User requests to find all persons in the displayed person list with names matching the input keyword(s).
CulinaryContacts shows all persons in the displayed person list with matching names.
Use case ends.
Extensions
1a. No keywords are provided.
1a1. CulinaryContacts shows an error message.
Use case resumes from step 1.
Use case: UC06 - Filter persons by tag
MSS
User requests to list all persons in the contacts list (UC03) or list all persons in the archived list (UC09).
User requests to find all persons in the displayed person list with specific tag(s).
CulinaryContacts shows all persons in the displayed person list matching all tags entered.
Use case ends.
Extensions
1a. No tags are provided.
1a1. CulinaryContacts shows an error message.
Use case resumes from step 1.
Use case: UC07 - Delete a person
MSS
User requests to list all persons in the contacts list (UC03) or list all persons in the archived list (UC09).
User requests to delete a specific person in the displayed person list.
CulinaryContacts deletes the person.
Use case ends.
Extensions
1a. The displayed person list is empty.
Use case ends.
2a. The given index is invalid.
2a1. CulinaryContacts shows an error message.
Use case resumes from step 2.
Use case: UC08 - Clear all entries
MSS
User requests to clear all entries.
CulinaryContacts asks for confirmation to clear all entries.
User confirms to clear all entries.
CulinaryContacts clears all entries.
Use case ends.
Extensions
2a. Confirmation is not given.
2a1. CulinaryContacts cancels the clear action.
Use case ends.
Use case UC09: List all persons in archived list
MSS
User requests to show all contacts in the archived list.
CulinaryContacts shows all persons in the archived list.
Use case ends.
Use case UC10: Archive a person
MSS
User requests to list all persons in the contacts list (UC03).
User requests to archive a specific person in the contacts list.
CulinaryContacts archives the person.
Use case ends.
Extensions
1a. The list is empty.
Use case ends.
2a. The given index is invalid.
2a1. CulinaryContacts shows an error message.
Use case resumes at step 2.
Use case: UC11 - Unarchive a person
MSS
User requests to list all persons in archived list (UC09).
User requests to unarchive a specific person in the archived list.
CulinaryContacts unarchives the person.
Use case ends.
Extensions
1a. The list is empty.
Use case ends.
2a. The given index is invalid.
2a1. CulinaryContacts shows an error message.
Use case resumes at step 2.
Use case UC12: Add a reservation
MSS
User requests to add a new reservation for a person.
CulinaryContacts adds the new reservation to the reservations list.
Use case ends.
Extensions
1a. The provided field(s) is/are invalid.
1a1. CulinaryContacts shows an error message.
Use case resumes from step 1.
1b. Compulsory field(s) is/are missing.
1b1. CulinaryContacts shows an error message.
Use case resumes from step 1.
1c. Another reservation made by the same person, on the same date, and at the same time already exists in the reservations list.
1c1. CulinaryContacts shows an error message.
Use case resumes from step 1.
Use case UC13: Delete a reservation
MSS
User requests to delete a specific reservation in the reservations list.
CulinaryContacts deletes the reservation.
Use case ends.
Extensions
1a. The reservations list is empty.
Use case ends.
2a. The given index is invalid.
2a1. CulinaryContacts shows an error message.
Use case resumes from step 2.
Use case UC14: Sort reservations
MSS
User requests to sort all reservations.
CulinaryContacts shows a sorted list of all reservations.
Use case ends.
Use case UC15: Exit program
MSS
User requests to exit the program.
CulinaryContacts exits.
Use case ends
11 or above installed.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
a. Download the jar file and copy into an empty folder.
b. Double-click the jar file.
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimal.
Saving window preferences
a. Resize the window to an optimal size. Move the window to a different location. Close the window.
b. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
Viewing the contacts list
a. Prerequisites: None
b. Test case: list
Expected: The contacts list is shown. The ‘contacts’ tab is underlined indicating that it is the current active tab.
Viewing the archived list
a. Prerequisites: None
b. Test case: alist
Expected: The archived list is shown. The ‘archived’ tab is underlined indicating that it is the current active tab.
Removing all persons and reservations from CulinaryContacts.
a. Prerequisites: None
b. Test case: clear, followed by n or any other input.
Expected: All persons and reservations remain unchanged. A Clear cancelled! message will be shown in the result display.
c. Test case: clear, followed by y.
Expected: All persons and reservations will be deleted. A Clear successful! message will be shown in the result display.
Opening the help window to view the command summary
a. Prerequisites: The help window is not open.
b. Test case: help
Expected: The help window is opened.
c. Test case: Press F1
Expected: The help window is opened.
d. Test case: Click Help button at the top, then click Help F1 button in the drop-down menu.
Expected: The help window is opened.
Copying the user guide website address
a. Prerequisites: The help window is opened.
b. Test case: Click on the Copy URL button, then paste it in the address bar of an external web browser.
Expected: The website address is copied to clipboard and the website is accessible.
Closing the help window
a. Prerequisites: The help window is opened.
b. Test case: Press q
Expected: The help window is closed.
c. Test case: Click the X button on top right corner of the help window.
Expected: The help window is closed.
Archiving a person while viewing the contacts list
a. Prerequisites: The user is viewing the contacts list. There is at least 1 person in the contacts list.
b. Test case: archive 1, followed by alist
Expected: The archived person is removed from the contacts list. This archived contact can be seen by executing the alist command to view the archived list. Details of the archived contact are shown in the status message.
c. Test case: archive 0
Expected: No person is archived. Result display shows error message: Invalid command format!.
d. Other incorrect delete commands to try: archive, archive x, ... (where x is larger than list size)
Expected: Similar to previous.
Archiving a person while viewing the archived list
a. Prerequisites: The user is viewing the archived list. There is at least 1 person in the archived list.
b. Test case: archive 1
Expected: Result display shows error message: This command can only be used while viewing the active contacts list. No person is archived.
Unarchiving a person while viewing the archived list
a. Prerequisites: List all archived persons using the alist command. There is at least 1 person in the archived list.
b. Test case: unarchive 1, followed by list
Expected: First contact is removed from the archived list. This unarchived contact can be seen by executing the list command to view the contacts list. Details of the unarchived contact are shown in the status message.
c. Test case: unarchive 0
Expected: No person is unarchived. Result display shows error message: Invalid command format!.
d. Other incorrect delete commands to try: unarchive, unarchive x, ... (where x is larger than list size)
Expected: Similar to previous.
Unarchiving a person while viewing the contacts list
a. Prerequisites: The user is viewing the contacts list. There is at least 1 person in the contacts list.
b. Test case: unarchive 1
Expected: Result display shows error message: This command can only be used while viewing the archived list. No person is unarchived.
Adding a new reservation for the first person in the displayed person list.
a. Prerequisites: There is at least 1 person in the displayed person list. There are no existing reservations made by the first person on 17/04/2024 at 6.00pm.
b. Test case: rsv 1 d/2024-04-17 t/1800 p/8
Expected: A new reservation is added to the reservations list. Name and phone number of the person, as well as date, time and number of people will be displayed in the reservation card.
Adding a duplicate reservation with the same date and time
a. Prerequisites: There is at least 1 person in the displayed person list. There is an existing reservation made by the first person on 17/04/2024 at 6.00pm.
b. Test case: rsv 1 d/2024-04-17 t/1800 p/5
Expected: Result display shows error message: This person has already made a reservation at this date and timing in the address book. No new reservation is added to the reservations list.
Deleting the first reservation in the reservations list
a. Prerequisites: There is at least 1 reservation in the reservations list.
b. Test case: rsvdel 1
Expected: First reservation is deleted from the reservations list. Details of the reservation shown in the result display.
c. Test case: rsvdel 1000
Expected: Result display shows error message: The reservation index provided is invalid. No reservation is deleted from the reservations list.
Sorting all reservations
a. Prerequisites: Multiple reservations in the reservations list. There is at least 1 non-expired reservation and 1 expired reservation in the reservations list. There is at least 1 person in the displayed person list.
b. Test case: rsv 1 d/2024-09-25 t/1800 p/4, followed by rsvsort
Expected: The new reservation is added to the bottom of the reservations list. After the rsvsort command is called, the reservations list is now sorted in the correct order.
Team size: 4
NAME of the person preventing addition of duplicate names. This is too restrictive as persons with the same name are quite common in reality. The user may also want to only record the first or last name which may cause more duplicate names. We plan to introduce a new ID field as a unique identifier for each contact, which will allow duplicate names to be recorded.NAME or PHONE NUMBER in the contacts list, these changes are not reflected in existing reservations made for that contact. As a result, the reservation records become inconsistent with the updated contact details. We plan to enhance this feature by ensuring that any updates to a contact in the contacts or archived list will automatically update the contact's details in the reservations list. For example, if the contact John Doe's phone number is updated, all existing reservations under John Doe's name will automatically reflect this new phone number.NAME, PHONE, EMAILand ADDRESS of the contact as all these fields are mandatory. This requirement can create difficulties if the user lacks information for all these fields. We plan to make the PHONE, EMAILand ADDRESS fields optional, so that it is more convenient for the user to add new contacts.INDEX is less than 1 or greater than 2147483647: The current error message which shows when the INDEX is less than 1 and exceeds the maximum integer size is ‘Invalid command format’, which might not be clear for the user. We plan to show the error message The person index provided is invalid for these cases.