By: W15-4      Since: Feb 2020      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

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 deletepet 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for deletepet 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component
UiCalendarDiagram
Figure 5. Structure of the Calendar Component in UI
UiDisplayListDiagram
Figure 6. Structure of the DisplayList Component in UI

API : Ui.java

The UI consists of a MainWindow class that is made up of parts which can be classified broadly into 2 groups:

  • (Group 1) Parts that are always displayed at all times, which include CommandBox, FeedbackDisplay, StatusBarFooter, etc. These parts appear above MainWindow in the class diagram for UI.

  • (Group 2) Parts that are selectively displayed, depending on the command entered by the user. Only some of these parts will be shown at any one instance. These include the Calendar and DisplayList components, and OverallStatistics. These parts appear beneath MainWindow in the class diagram for UI.

All the UI classes, 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.

In addition, each UI part has been styled using CSS. The custom CSS styling rules are defined in multiple CSS stylesheets, which can be found in the src/main/resources/view/stylesheets folder.

The UI component does the following:

  • Executes user commands using the Logic component.

  • Listens for changes to Model data to update the UI with the modified data.

  • Handles a returned CommandResult to perform additional actions, e.g. show the help window, exit the program, display the appropriate part or component from Group 2, etc.

2.3. Logic component

LogicClassDiagram
Figure 7. Structure of the Logic Component

API : Logic.java

  1. Logic uses the PetTrackerParser 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 pet).

  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("deletepet 1") API call.

DeleteSequenceDiagram
Figure 8. Interactions Inside the Logic Component for the deletepet 1 Command
The lifeline for DeletePetCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. Model component

ModelClassDiagram
Figure 9. Structure of the Model Component

API : Model.java

The Model,

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

  • stores the Pet Tracker data. Note that the Pet Tracker keeps track of both the schedule system and the pet system.

  • exposes an ObservableList<Pet>, an ObservableList<Slot>, and an ObservableList<FoodCollection> that are unmodifiable and 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.

2.5. Storage component

StorageClassDiagram
Figure 10. 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 Pet Tracker data in json format and read it back.

2.6. Common classes

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

3. Implementation

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

3.1. Display

3.1.1. Implementation

The display mechanism is facilitated by an ObservableList of DisplayItem called filteredDisplayItems, which is an attribute stored in ModelManager.

Any class that is to be displayed as an item in a list implements the DisplayItem interface. This interface has a single method named getDisplaySystemType which returns the type of system to be displayed. In our program, the Pet, Slot and FoodCollection classes implement this interface.

Step 1. The user opens the app the the 1st time. A few things happen at start-up:

  • In Model (ModelManager), filteredDisplayItems is created, and is set to bind to filteredPets. This way, filteredDisplayItems contains all the elements of filteredPets, and any changes to filteredPets will also be automatically propogated to filteredDisplayItems.

  • In the MainWindow, a DisplayListPanel and a CalendarPanel are initialized. The DisplayListPanel is created with filteredDisplayItems as its backing list, while the CalendarPanel will be initialized with the List of Slot`s obtained from `logic.getPetTracker().getSlotList().

  • The resultDisplayPlaceholder component in the MainWindow is set to display the DisplayListPanel. As such, the user sees the list of pets as the initial display.

The following ____ diagram summarises Step 1 and shows what happens at initialization: (WIP)

displayDiagram1

Step 2. The user executes display s to have the slots displayed in a list. The display command calls Model#changeDisplaySystem, which causes filteredDisplayItems to be re-binded to filteredSlots instead. Because the display is still making use of DisplayListPanel, no change is made to resultDisplayPlaceholder afterwards.

Step 3. The user executes display c to have the slots displayed in calendar view. Since filteredDisplayItems is not used for displaying the calendar, it is not changed when the display command calls Model#changeDisplaySystem. Upon receiving back the result of the command in MainWindow, resultDisplayPlaceholder is changed to display the CalendarPanel instead of the DisplayListPanel.

Step 4. The user executes display p to view the list of pets. The display command calls Model#changeDisplaySystem, which causes filteredDisplayItems to re-binded to filteredPets. Since the program should now display a list of items instead of a calendar, upon receiving back the result of the command in MainWindow, resultDisplayPlaceholder is changed to display the DisplayListPanel from CalendarPanel.

The following ____ diagram shows how the display operation works: (WIP)

displayDiagram2

3.2. Schedule feature

3.2.1. Implementation

The schedule feature uses instances of class Slot to organise bathing schedule for the pets. Each Slot contains a starting time of the bath, stored internally as a LocalDateTime, and the duration of the bath stored internally as a Duration. It stores a reference to the Pet in the ModelManager as specified by the user.

Given below is an example usage scenario and how the Schedule mechanism behaves at each step.

Step 1. The user launches the application with some pets stored (Garfield, for instance). ObservableList<Slot> in Schedule is currently empty.

Step 2. The user executes addslot n/Garfield t/1/4/2020 1200 d/120 command to create a Slot for Garfield. The AddSlotCommandParser calls parsePet() in SlotParserUtil, which then takes in the Model passed in to find a reference for the specific Pet with Model.getPet(). Prior to this stage, if the name string is invalid, a ParseException(MESSAGE_INVALID_PETNAME) will be thrown. Or the program cannot find the Pet in the model, a ParseException(MESSAGE_PET_DOES_NOT_EXIST) will be thrown. This ensures that every slot created actually points to an existing Pet found in PetTracker.

If parsePet() fails its execution, no new Slot is created.

Step 3. New Slot is created.

Step 4. The user now decides that this exact slot should be occupied by another pet, and decides to edit it, executing the editslot command.

Step 5. SlotParserUtil is used again to create a reference to a pet in the ModelManager.

Step 6. The user now decides that they need to see slots occupied by a particular pet on a particular date, executing the findslots n/Garfield t/1/4/2020 command.

Step 7. The FindSlotCommand reduces the two predicates* and pass it to ModelManager to create a filtered list of slots.

*The FindSlotCommand uses the following classes which both inherit Predicate<Slot> to search for the user specified slots:

  • SlotPetNamePredicate() — Internally stores the Name to search for, and compares it with getPet().getName().fullName.

  • SlotDateTimePredicate() — Internally stores the LocalDateTime to search for (Timing will be ignored), and compares it with getDate().

3.2.2. Design Considerations

Aspect: How schedule stores the pets internally
  • Alternative 1 (current choice): Makes a reference to the the memory address in ModelManager .

    • Pros: When the pet is edited, the slot is also updated.

    • Cons: Hard to implement and test.

  • Alternative 2: Simply create a new Pet.

    • Pros: Easy to implement and test (A refactor of Pet), low coupling with Model.

    • Cons: Does not update when original pet is edited, which is not something the user will expect.

3.3. Inventory feature

3.3.1. Implementation

The Inventory feature gives a summary of all the food items involved in a pet tracker system. It is supported by FoodCollection which resembles a collection of food of the same type and FoodCollectionList which is a list of these collections. A FoodCollectionList is stored as an attribute of UniquePetList for the following reasons:

  • The list of FoodCollection items associated with a UniquePetList can be directly derived from the UniquePetList itself.

  • Changes in FoodCollection occurs only if there is a change in UniquePetList#internalList.

Data stored in FoodCollectionList is exposed to ModelManager through UniquePetList and PetTracker as an unmodifiable ObservableList<FoodCollection>. ModelManager then passes the list of FoodCollection to ui for display as a list of DisplayItem when display i is called.

The following shows a typical usage scenario that involves the Display Inventory feature.

  • Step 1: The user launches the application. A UniquePetList is initialized in PetTracker, upon which a FoodCollectionList item is created to store the food data of the pets in the list(if it is an empty list, FoodCollectionList is also stores an empty list of FoodCollection)

  • Step 2: The user executes 'display i' command. The display command calls Model#ChangeDisplaySystem() and the i display type determines the displayed list is switched to ObservableList<FoodCollection>. Model$getFilteredDisplayList() then acquires the list and sends it to Ui unit for display.

  • Step 3: The user inputs a command that modifies the UniquePetList, e.g 'editpet 1 f/catfood:100'. UniquePetList$internalList is an instance of ObservableList<Pet>. Thus when it is modified, a ListChangeListener<Pet> is woken up and it calls UniquePetList$updateFoodCollectionList() to update the FoodCollectionList according to the modified Pet list.

The sequence diagram below is an illustration of the flow of events that happen in the logical component when Step 2 above occurs.

DisplayInventorySequenceDiagram
Figure 11. Interactions Inside the Logic Component for the display i Command

3.3.2. Design Considerations

Aspect: Maintaining the collection of food in a pet tracker
  • Alternative 1(current choice): Maintains the list as an attribute of UniquePetList.

    • Pros: Easier to initialize and update the list.

    • Cons: Less extendability. Adding additional food items in inventory(independent of pet list) is difficult.

  • Alternative 2: Maintains a list of food collections separate from UniquePetList.

    • Pros: Higher Extendability that supports more independent operations of FoodCollection List.

    • Cons: More difficult to constantly update and maintain the food collection list should food list changes.

Aspect: Updating the collection of food when pet list is modified.
  • Alternative 1(current choice): Replace the entire list by a new food collection list created from the updated pet list.

    • Pros: Easy to implement and no adaptation is required for different types of modification of pet list.

    • Cons: Computationally intensive when there is a huge pet list.

  • Alternative 2: Modify FoodCollection affected by the command.

    • Pros: Less computationally intensive and more responsive given a large database.

    • Cons: Adaptations for each pet related commands is required since the food list can be affected in different ways.(e.g addition, modification, deletion)

3.4. 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 3.5, “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

3.5. Configuration

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

3.6. Statistics

We are generating the overall statistics of Pet Store Helper and translate the data in a user-friendly manner.

  • OverallStatistics under UI component handles the translation of three sets of data: list of pets, schedule, and list of inventory.

  • Data is obtained from Logic.

How we implemented overall statistic on UI:

  • The statistics for pets are shown in a form of pie chart, while the pets are grouped according to their species.

  • The schedule statistics is in the form of a timetable of recent 3 days. Each slot is represented as a shaded rectangle in the timetable.

  • The inventory data are generated from the list of pets, and grouped together by their names, such that users have a better understanding of overall food consumption. The list of inventory is represented as a bar chart.

Following is the sequential diagram of the command stats StatsSequenceDiagram

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to manage their pet store with a variety of animals and features

  • has a need to make schedules for pet grooming and ensure no-conflict in the scheduling

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: manage pets, pet consumables and schedule faster than a typical mouse/GUI driven app

Appendix B: User Stories

Priorities: High (must have) - * * *, Low (nice to have) - * *

Priority As a …​ I want to …​ So that I can…​

* * *

user

key in a new pet, enter its breed, age, size and food consumption.

keep track of the pets I have in my store and their details

* * *

user

delete a pet

remove pets that I have sold or no longer taking care of

* * *

user

find a pet by name, species or tags

locate details of the pets without having to go through the entire list

* * *

user

keep track of pet food, cleaning products and other consumables

not run low on items needed to keep the pets healthy

* * *

user

schedule when to bathe my own (in-store) pets

avoid clashes in bathing schedule

* * *

user

view the schedule and see which slots are available to bathe the customers' pets

avoid clashes in bathing schedule

* *

user

see which free slots are available for grooming

avoid clashes in grooming

* *

user

view a statistical summary of the pets, stocks and schedule

handle logistics of the store more efficiently

* *

user

add photos for the pets in store to illustrate

easier to make a mental link between the actual pets in the store and the names

* *

user

keep track of the cost and revenue generated by each pet

so to buy the more popular ones in next restock

Appendix C: Use Cases

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

Use case: Delete pet

MSS

  1. User requests to list pets

  2. PSH shows a list of pets

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

  4. PetTracker deletes the pet

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. PSH shows an error message.

      Use case resumes at step 2.

Use case: Removing a bathing slot

MSS

  1. User requests to show schedule

  2. PSH shows schedule of that day

  3. User requests of delete a slot at a specified timing

  4. PSH deletes the slot

    Use case ends.

Extensions

  • 2a. There is currently conflict in the scheduling (i.e. One slot begins before the previous one ends), the latter slot is shown in red.

    Use case resumes at step 2

  • 3a. The given timing does not exist.

    • 3a1. PSH shows an error message.

      Use case resumes at step 2.

Appendix D: Non Functional Requirements

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

  2. Should be able to hold up to 500 pets + items in total without a noticeable sluggishness in performance for typical usage.

  3. 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.

{More to be added}

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Appendix F: Instructions for Manual Testing

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.

F.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 pets and slots. 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.

{ more test cases …​ }

F.2. Deleting a pet

  1. Deleting a pet while all pets are displayed

    1. Prerequisites: Display all pets using the display p command. Multiple pets in the display.

    2. Test case: deletepet 1
      Expected: First pet is deleted from the list. Details of the deleted pet shown in the status message. Timestamp in the status bar is updated.

    3. Test case: deletepet 0
      Expected: No pet is deleted. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect delete commands to try: deletepet, deletepet x (where x is larger than the list size) {give more}
      Expected: Similar to previous.

{ more test cases …​ }

F.3. Saving data

  1. Dealing with missing/corrupted data files

    1. {explain how to simulate a missing/corrupted file and the expected behavior}

{ more test cases …​ }