By: W15-4
Since: Feb 2020
Licence: MIT
1. Setting up
Refer to the guide here.
2. Design
2.1. Architecture

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

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
.

deletepet 1
commandThe sections below give more details of each component.
2.2. UI component



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 aboveMainWindow
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
andDisplayList
components, andOverallStatistics
. These parts appear beneathMainWindow
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

API :
Logic.java
-
Logic
uses thePetTrackerParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a pet). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
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.

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

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>
, anObservableList<Slot>
, and anObservableList<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

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 tofilteredPets
. This way,filteredDisplayItems
contains all the elements offilteredPets
, and any changes tofilteredPets
will also be automatically propogated tofilteredDisplayItems
. -
In the
MainWindow
, aDisplayListPanel
and aCalendarPanel
are initialized. TheDisplayListPanel
is created withfilteredDisplayItems
as its backing list, while theCalendarPanel
will be initialized with theList
ofSlot`s obtained from `logic.getPetTracker().getSlotList()
. -
The
resultDisplayPlaceholder
component in theMainWindow
is set to display theDisplayListPanel
. 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)

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)

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 theName
to search for, and compares it withgetPet().getName().fullName
. -
SlotDateTimePredicate()
— Internally stores theLocalDateTime
to search for (Timing will be ignored), and compares it withgetDate()
.
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 withModel
. -
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 aUniquePetList
can be directly derived from theUniquePetList
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 inPetTracker
, upon which aFoodCollectionList
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 ofFoodCollection
) -
Step 2: The user executes 'display i' command. The
display
command calls Model#ChangeDisplaySystem() and thei
display type determines the displayed list is switched toObservableList<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 ofObservableList<Pet>
. Thus when it is modified, aListChangeListener<Pet>
is woken up and it callsUniquePetList$updateFoodCollectionList()
to update theFoodCollectionList
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.

display i
Command3.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 usingLogsCenter.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
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
-
User requests to list pets
-
PSH shows a list of pets
-
User requests to delete a specific pet in the list
-
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
-
User requests to show schedule
-
PSH shows schedule of that day
-
User requests of delete a slot at a specified timing
-
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
-
Should work on any mainstream OS as long as it has Java
11
or above installed. -
Should be able to hold up to 500 pets + items in total without a noticeable sluggishness in performance for typical usage.
-
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 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
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample pets and slots. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
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
-
Deleting a pet while all pets are displayed
-
Prerequisites: Display all pets using the
display p
command. Multiple pets in the display. -
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. -
Test case:
deletepet 0
Expected: No pet is deleted. Error details shown in the status message. Status bar remains the same. -
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
-
Dealing with missing/corrupted data files
-
{explain how to simulate a missing/corrupted file and the expected behavior}
-
{ more test cases … }