remark
command in this project was implemented with reference to the CS2103T AB3 Tutorial: Adding a command.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
, ClientListPanel
, 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
objects (which are contained in a UniquePersonList
object).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.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.address.commons
package.
This section describes some noteworthy details on how certain features are implemented.
The view
command allows users to view the details of a client on the GUI using their INDEX
. Other commands will also affect the client display in the GUI. This includes information not included in the client list cards, such as their last met and policy list.
The view client mechanism is facilitated by DisplayClient
in the model. There are three possible outcomes when a command is executed:
add
) or referring to a client using INDEX
(e.g. view
, met
,deletepolicy
) is executed, the DisplayClient
is set to the client that was operated on.list
, sort
, find
), the DisplayClient
is set to the first client in the new list.delete
or clear
is executed, the DisplayClient
is set to null
.
This is done with the setDisplayClient()
function in the Model
, that is also implemented in Logic
.The sequence diagram below shows the execution of view 1
to view the details of client at index 1.
MainWindow
handles most of the UI logic in regard to displaying the viewed client on the GUI, including refreshing the ClientDetailsPanel
and ClientPolicyTable
. It also sets DisplayClient
on startup to the first client in the list when there is at least one client, otherwise it sets DisplayClient
to null
.
Aspect: Where DisplayClient
should be stored or handled.
DisplayClient
is stored and handled in Model
, with relevant functions in Logic
.
Model
and Logic
are similar to those for AddressBook
to get and set the DisplayClient
.ObservableList<Person>
for the GUI is separate from the AddressBook
.DisplayClient
to be used even when there is no command executed. For example, when the application starts up, it displays the first client in the list, despite no command execution.DisplayClient
is handled in CommandResult
.
DisplayClient
would simply be a Person
set by CommandResult
, similar to the current feedbackToUser
implementation.DisplayClient
can only be set after a command, which does not allow us to set DisplayClient
on application startup.The remark
command allows users to add an optional note to a client.
The remark
command was implemented according to Tutorial: Adding a command from CS2103T and AB3. The mechanism is similar to edit
, and is facilitated by RemarkCommand
. It creates and returns a personToEdit
, where only the Remark
is updated to the new remark entered by the user. Changes are made using Model#setPerson(Person, Person)
.
Aspect: Behaviour of r/
prefix if more than one is used.
Remark
.
remark 1 r/typo r/corrected
will only capture corrected
.r/
prefixes.
r/
in their remarks. It also means fixing typos will be slower, like mentioned above.r/
prefix.
remark INDEX REMARK
instead.ArgumentMultimap
, deviating from other commands.The sort
command allows users to sort the client list by a specified sort criteria
that can be name
, priority
or birthday
, and a sort order
that can be asc
or desc
.
The functionality to sort
clients is implemented in the SortCommand
class. The SortCommandParser
class is responsible for parsing the user input and creating a SortCommand
object.
The SortCommandParser
class parses the input arguments by storing the prefixes of their respective values in a ArgumentMultimap
object, and create a new SortCommand
object with the parsed SortCriteria
and SortOrder
.
The SortCommand
object does the following:
PersonComparator#getComparator(SortCriteria, SortOrder)
is used to get the Comparator<Person>
object using the SortCriteria
and SortOrder
.Model#updateSortPersonComparator(Comparator<Person>)
- Updates the Comparator<Person>
object used to sort the list of persons in the Model
component.Model#setDisplayClientAsFirstInSortedFilteredPersonList()
- Updates the displayed client in the UI to the first client in the sorted list of persons.The following object diagram illustrates the above:
The following sequence diagram shows the sort
operation:
In order to keep ModelManager#filteredPersons
as an immutable final
field, we have decided not to modify the filteredPersons
directly. Instead, we do the following:
Comparator<Person>
object in ModelManager#personComparator
, which can be updated by ModelManager#updateSortPersonComparator(Comparator<Person>)
.ModelManager#getSortedFilteredPersonList()
which returns a new sorted list of persons sorted using the ModelManager#personComparator
.This way, the original order of ModelManager#filteredPersons
is preserved, and we can get a sorted list of persons when needed.
The last met feature allows users to keep track and update their last interaction with their clients.
The updating of last met command is facilitated by the LastMetCommandParser
class which is created by the AddressBookParser
.
The LastMetCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
LastMetCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object.LastMetCommand
object with the formatted date.The LastMetCommand
object is then executed by the Logic
component.
The LastMetCommand
object then communicates with the Model
component to update the LastMet to the client. The Model
component then updates the Person
object with the new LastMet.
Model#setPerson(Person, Person)
- Sets the client in the existing client list to the new Person
object which has been edited by the LastMetCommand#execute()
which contains the new LastMet.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been edited with the new LastMet.The method LastMetCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
The following object diagram illustrates the above:
The following sequence diagram shows the lastmet operation:
The setting last met overdue duration feature allows users to choose the number of days before clients show up in the Last Met Display.
The updating of last met command is facilitated by the SetCommandParser
class which is created by the AddressBookParser
.
The SetCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
SetCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object.SetCommand
object with the formatted integer.The SetCommand
object is then executed by the Logic
component.
The SetCommand
object then communicates with the Model
component to update the static lastMetDuration value in the Last Met class.
Upon updating the new lastMetDuration value, the SetCommand
object then calls the checkOverdue
function in all the Person
objects in the addressbook
to update the isOverdue
boolean in all the Person
objects. The Last Met Display then shows all the updated Person
objects with isOverdue
equals to true
.
The method SetCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
The adding schedule feature allows users to make appointments to track all their upcoming appointments with clients.
The updating of schedule command is facilitated by the ScheduleCommandParser
class which is created by the AddressBookParser
.
The ScheduleCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
ScheduleCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object.ScheduleCommand
object with the formatted dateTime.The ScheduleCommand
object is then executed by the Logic
component.
The ScheduleCommand
object then communicates with the Model
component to update the Schedule to the client. The Model
component then updates the Person
object with the new Schedule.
Model#setPerson(Person, Person)
- Sets the client in the existing client list to the new Person
object which has been edited by the ScheduleCommand#execute()
which contains the new Schedule.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been edited with the new Schedule.The method ScheduleCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
Aspect: Letting users set multiple appointments per client.
The marking schedule feature allows users to close upcoming appointments to track all their upcoming appointments with clients.
The marking of schedule command is facilitated by the MarkCommandParser
class which is created by the AddressBookParser
.
The MarkCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
MarkCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object.MarkCommand
object with the formatted dateTime.The MarkCommand
object is then executed by the Logic
component.
The MarkCommand
object then communicates with the Model
component to update the Schedule to the client. The Model
component then updates the Person
object with the new Schedule with isDone
set to true
.
Model#setPerson(Person, Person)
- Sets the client in the existing client list to the new Person
object which has been edited by the MarkCommand#execute()
which contains the new Schedule.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been edited with the new Schedule.The method MarkCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
Aspect: Marking an appointment updates the last met for the client.
met
to update the last met of the client separately.schedule
command.The add policy feature allows users to add a policy to a client. The policy is stored in the Policy
class, which contains the policy details such as policy name, policy id. The Policy
class is then added to the PolicyList
object stored within the Person
object in the Model
component.
The add policy command mechanism is facilitated by the AddPolicyCommandParser
class which is created by the AddressBookParser
.
The AddPolicyCommandParser
class is responsible for parsing the user input and creating an AddPolicyCommand
object.
The AddPolicyCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
AddPolicyCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object, and creates a new AddPolicyCommand
object with the parsed policy name and policy ID.The AddPolicyCommand
object is then executed by the Logic
component.
The AddPolicyCommand
object then communicates with the Model
component to add the policy to the client. The Model
component then updates the Person
object with the new policy.
Model#setPerson(Person, Person)
- Sets the client in the existing client list to the new Person
object which has been edited by the AddPolicyCommand#execute()
which contains the new policy.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been edited with the new policy.The method AddPolicyCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
The following object diagram illustrates the above:
The following sequence diagram shows the addpolicy operation:
The following activity diagram shows what happens when a user adds a policy:
The delete policy feature allows users to delete a policy from a client. The Policy
object corresponding to the specified policy in the PolicyList
object stored within the specified Person
object in the Model
component is removed.
The delete policy command mechanism is facilitated by the DeletePolicyCommandParser
class which is created by the AddressBookParser
.
The DeletePolicyCommandParser
class is responsible for parsing the user input and creating a DeletePolicyCommand
object.
The DeletePolicyCommandParser#parse()
overrides Parser#parse()
in the Parser
interface.
DeletePolicyCommandParser#parse()
- Parses the input arguments by storing the prefixes of it respective values in a ArgumentMultimap
object, and creates a new DeletePolicyCommand
object with the parsed policy ID.The DeletePolicyCommand
object is then executed by the Logic
component.
The DeletePolicyCommand
object then communicates with the Model
component to delete the policy from the client. The Model
component then updates the Person
object with the policy removed.
Model#setPerson(Person, Person)
- Sets the client in the existing client list to the new Person
object which has been edited by the DeletePolicyCommand#execute()
which has the policy removed.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been edited with the policy removed.The method DeletePolicyCommand#execute()
returns a CommandResult object which contains the success message to be displayed to the user.
The following object diagram illustrates the above:
The following sequence diagram shows the deletepolicy operation:
Aspect: Deleting a policy using PolicyID instead of PolicyName.
The add birthday and edit birthday features allow users to add and edit the birthday of a client. Birthdays support the birthday reminders feature. The birthday is stored in the Birthday
class, which contains the birthday details such as day, month, and year. The Birthday
class is part of the Person
object in the Model
component.
The add priority and edit priority features allow users to add and edit the priority of a client. Priority supports the sort by priority feature, and helps optimise client management. The priority is stored in the Priority
class, which contains the priority details such as priority value. The priority value are enumerated, and can be one of the following: LOW
, MEDIUM
, HIGH
, VIP
. The Priority
class is part of the Person
object in the Model
component.
The functionality to add and edit birthday and priority is implemented in the AddCommand
and EditCommand
classes. The AddCommandParser
and EditCommandParser
classes are responsible for parsing the user input and creating an AddCommand
or EditCommand
object respectively.
The AddCommandParser
and EditCommandParser
classes parse the input arguments by storing the prefixes of their respective values in a ArgumentMultimap
object, and create a new AddCommand
or EditCommand
object with the parsed birthday or priority, amongst other fields.
The AddCommand
and EditCommand
objects then communicate with the Model
component to add or edit the birthday or priority of the client. The Model
component then adds or edits the Person
object with the new birthday or priority, amongst other fields.
The AddCommand
object then communicates with the Model
component to add a person.
Model#addPerson(Person)
- Adds the new client to the existing client list.Model#setDisplayClient(Person)
- Updates the displayed client in the UI to the client that has been added.The following object diagram illustrates the above:
The following sequence diagram shows the add
operation:
More on Birthday
class
LocalDate
object, as time is not relevant for birthday.DateUtil
common class to ensure that the date is valid and in the correct format.DateUtil
class is used to validate (conforms to DateUtil
date format and is parsable) and parse the string to a LocalDate
object. DateUtil
is also used to ensure that the date is not in the future.DateUtil
class for more information on the date format and parsing.More on Priority
class
PriorityValue
object, which is an enumerated type, to ensure that priority value is a valid type.PriorityValue
enum class which should be responsible for the toString()
logic for display.PriorityValue
enum class is used to validate the priority value, which is responsible for the possible valid priority values.PriorityValue
enum class for more information on the priority values.More on PriorityValue
enum class
PriorityValue
is an enumerated type that contains the possible valid priority values: LOW
, MEDIUM
, HIGH
, VIP
.PriorityValue
allows full form values (low
, medium
, high
, vip
) and short form values (l
, m
, h
, v
) to be used interchangeably.PriorityValue
object is case-insensitive, and is handled by getPriority
.PriorityValue
object is handled by getFullPriorities()
and getShortPriorities()
respectively.HashMap<String, PriorityValue> FULL_PRIORITY_MAP
and HashMap<String, PriorityValue> SHORT_PRIORITY_MAP
, which has a constant time complexity.Target user profile:
Value proposition:
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | insurance agent | see usage instructions | refer to instructions when I forget how to use the App |
* * * | insurance agent | add a new client contact details | keep track of the clients I have |
* * * | insurance agent | delete a client | remove clients that are leaving |
* * * | insurance agent | find a client by name | locate details of client without having to go through the entire list |
* * * | insurance agent | list all clients | see all clients at a glance |
* * * | insurance agent | view client information | know and check client details |
* * | insurance agent | check schedules with clients on a date | keep track of what I have to do in a day |
* * | insurance agent | add the birthday of my clients | wish them happy birthday to keep in contact with them |
* * | insurance agent | delete policy details for a client | remove expired policies of the client |
* * | insurance agent | see when I last met a client | check in on a client that I have not met for a long time |
* * | insurance agent | mark that a schedule is completed | know that i fulfilled the appointment scheduled |
* * | insurance agent | add policy details of a client | keep track of clients and their policies |
* * | insurance agent | schedule checkup date and time for clients | know when to follow-up with them |
* | insurance agent | set the overdue period for last met | be reminded of a follow-up at my own pace |
* | insurance agent | sort clients by priority | deal with client with higher priority status first |
* | insurance agent | track deals that I have closed | track my current progress |
* | insurance agent | edit my client's details | update my client's details |
* | insurance agent | reschedule my appointments | change the date and time of appointments with clients |
* | insurance agent | filter clients by importance | decide on who to prioritise on |
* | insurance agent | get help | use the app when I am lost or confused |
* | insurance agent | can sort clients by the expected revenue of the deals | know which clients to prioritise |
* | insurance agent | set the policy payment due dates | remind my clients. |
* | insurance agent | add the maturity date of my client’s policy | update them and plan for future policies |
* | developer | view list of all bugs reported by users | conveniently view all reported bugs and fix them |
* | colleague | import someone's contact list | take over his clients |
* | insurance agent | report issues/bugs | get someone to fix bugs |
* | developer | get a log list of user activity | view user activity to bug fix |
* | manager | view all my subordinates' clients | be aware of their progress and client base |
* | insurance agent | get reminders of client birthday | send birthday message |
(For all use cases below, the System is the ClientCare
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Add new client
MSS
Extensions
Use case: UC02 - Delete client
MSS
Extensions
Use case: UC03 - Edit client
MSS
Extensions
Use case: UC04 - List all clients
MSS
Extensions
Use case: UC05 - View client details and policies
MSS
Extensions
Use case: UC06 - Find a client by name
MSS
Extensions
Use case: UC07 - Adding notes to a client
MSS
Extensions
Use case: UC08 - Clear all client
MSS
Extensions
Use case: UC09 - Sort clients
MSS
CRITERIA
and ORDER
.Extensions
CRITERIA
is invalid.
ORDER
is invalid.
Use case: UC10 - Update client as met
MSS
Extensions
Use case: UC11 - Update last met overdue duration
MSS
Extensions
Use case: UC12 - Schedule an appointment with client
MSS
Extensions
Use case: UC13 - Mark appointment
MSS
Extensions
Use case: UC14 - Add policies to client
MSS
Extensions
Use case: UC15 - Delete policies from client
MSS
Extensions
11
or above installed.Given below are instructions to test the app manually. The full guide on the expected outcome and format of the commands can be found in our user guide. This appendix will serve to inform users on the assumptions along with a correct and invalid test case.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
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 contacts. 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.
Adding a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the list.
Test case: add n/John Doe c/12345678 e/john-doe@example.com a/123 Tampines Street 42 t/friends p/high d/1987-02-02
Expected: John Doe is added to the end of the list. Details of the added person are shown in the status message.
Test case (Missing Compulsory Parameter): add n/John Doe e/john-doe@example.com a/123 Tampines Street 42 t/friends p/high d/1987-02-02
Expected: No client is added to the list. Error details shown in the status message.
Test case (Invalid Parameter): add n/John Doe c/12345678 e/john-doe.example a/123 Tampines Street 42 t/friends p/high d/1987-02-02
Expected: Similar to previous.
Adding a client that is already in list
Prerequisites: List all clients using the list
command. Multiple clients in the list. There is a client with name John Doe
already in the list.
Test case: add n/John Doe c/12345678 e/john-doe@example.com a/123 Tampines Street 42 t/friends p/high d/1987-02-02
Expected: No client is added to the list. Error details shown in the status message.
Deleting a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the list.
Test case: delete 1
Expected: First client is deleted from the list. Details of the deleted contact shown in the status message.
Test case (Missing Index): delete
Expected: No client is deleted. Error details shown in the status message.
Test case (Invalid Index): delete x
(where x is smaller or larger than the list size)
Expected: similar to previous.
Editing a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the list.
Test case: edit 1 n/John Doe
Expected: First client's name is edited to John Doe. Details of the added person are shown in the status message.
Test case (Missing Index): edit n/John Doe
Expected: No client is edited. Error details shown in the status message.
Test case (Invalid Index): edit x n/John Doe
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test case (Missing Parameters): edit 2
Expected: Similar to previous.
Test case (Invalid Parameter): edit e/john-doe.example
Expected: Similar to previous.
Listing all clients
Prerequisites: Multiple clients in the client list.
Test case: list
Expected: All clients are shown in the list view. Success message shown in the status message.
Test case: list 1
, list asdsad
, list n/Jones
or any command with extra characters supplied
Expected: Similar to previous.
Viewing a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the client list.
Test case: view 2
Expected: Second client's details are shown in the client details view and policy details view. Success message shown in the status message.
Test case (Missing Index): view
Expected: Client details view and Policy details view not updated. Error details shown in the status message.
Test case (Invalid Index): view x
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test case (Extra Characters): view 1 asd
, view 1 n/Jones
or any command with extra characters supplied
Expected: Similar to previous.
Viewing a client while clients are filtered by name John
Prerequisites: Multiple clients with similar name (e.g. John Doe
, John Yu
) in client list. Filter the clients using the find john
command.
Test case: view 2
Expected: Second client's details are show in the client details view and policy details view. Success message shown in the status message.
Viewing a client while clients are sorted by priority in ascending order
Prerequisites: Multiple clients with different priorities in client list. Sort the clients using the sort priority o/asc
.
Test case: view 2
Expected: Second client's details are shown in the client details view and policy details view. Success message shown in the status message.
Finding a client with a given name Jones
Prerequisites: List all client using the list
command. Multiple clients in the client list. Ensure there is a client with the name "Jones".
Test case: find Jones
Expected: Client list update to show all clients with the name "Jones". Success message shown in the status message.
Test case (Multiple keywords): find Jones Brown
Expected: Client list update to show all clients with the name "Jones" or the name "Brown" (if any). Success message shown in the status message.
Test case (Missing keyword): find
Expected: No client is found. Error details shown in the status message.
Adding a note to a client while client does not have existing note
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure the first client does not have a note.
Test case: remark 1 r/Prefers emails
Expected: Note successfully added to first client. Success message shown in the status message.
Test case (Empty Parameter): remark 1 r/
Expected: Note successfully removed from first client. Success message show in the status message.
Test case (Repeated Parameters): remark 1 r/Preeeffers emaiis r/Prefers emails
Expected: Note from last parameter successfully added to first client. Success message shown in the status message.
Test case (No Parameter): remark 1
Expected: Note successfully removed from first client. Success message show in the status message.
Test case (Missing Index): remark r/Prefers emails
Expected: Note not added to any client. Error details shown in the status message.
Test case (Invalid Index): remark x r/Prefers emails
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Clearing the client list
Prerequisites: Multiple clients in the client list.
Test case: clear
Expected: All clients are removed from the list. Success message shown in the status message.
Test case: clear 1
, clear asdsad
, clear n/Jones
or any command with extra characters supplied
Expected: Similar to previous.
Sorting clients by priority
Prerequisites: Multiple clients in the client list.
Test case (valid descending): sort priority o/desc
Expected: Clients are sorted by priority in descending order. Success message shown in the status message.
Test case (valid ascending): sort priority o/asc
Expected: Clients are sorted by priority in ascending order. Success message shown in the status message.
Test case (invalid order): sort priority o/invalid
Expected: Clients are not sorted. Error message shown in the status message.
Test case (invalid criteria): sort invalid o/asc
Expected: Similar to previous.
Sorting clients by name
Prerequisites: Multiple clients in the client list.
Test case (valid ascending): sort name o/asc
Expected: Clients are sorted by name in ascending order. Success message shown in the status message.
Test case (valid descending): sort name o/desc
Expected: Clients are sorted by name in descending order. Success message shown in the status message.
Test case (invalid order): sort name o/invalid
Expected: Clients are not sorted. Error message shown in the status message.
Test case (invalid criteria): sort invalid o/asc
Expected: Similar to previous.
Sorting clients by birthday
Prerequisites: Multiple clients in the client list.
Test case (valid ascending): sort birthday o/asc
Expected: Clients are sorted by birthday in ascending order. Success message shown in the status message.
Test case (valid descending): sort birthday o/desc
Expected: Clients are sorted by birthday in descending order. Success message shown in the status message.
Test case (invalid order): sort birthday o/invalid
Expected: Clients are not sorted. Error message shown in the status message.
Test case (invalid criteria): sort invalid o/asc
Expected: Similar to previous.
Updating the last met of a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure the date chosen is not in the future.
For the test cases, we assume that today is 13 April 2024.
Test case: met 1 d/2024-04-11
Expected: Last met successfully updated for first client. Success message shown in the status message.
Test case (Invalid Date Format): met 3 d/11-04-2024
Expected: Last met not updated for any client. Error details in status message.
Test case (Missing Parameters): met 3
Expected: Similar to previous.
Test case (Repeated Parameters): met 3 d/2024-04-11 d/2024-04-11
or any command with repeated parameter
Expected: Similar to previous.
Test case (Missing Index): met d/2024-04-11
Expected: Similar to previous.
Test case (Invalid Index): met x d/2024-04-11
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test Case (Future Date, Invalid Date): met 3 d/2025-04-20
Expected: Similar to previous.
Test Case (Invalid Date): met 3 d/2024-02-31
Expected: Similar to previous.
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure the date chosen is in the future.
For the test cases, we assume that today is 13 April 2024 and the time is 2pm.
Test case: schedule 1 d/2025-04-18 18:00
Expected: Schedule successfully updated for first client. Success message shown in the status message.
Test case (Invalid DateTime Format): schedule 3 d/18-04-2025
Expected: Schedule not updated for any client. Error details in status message.
Test case (Missing Parameters): schedule 3
Expected: Similar to previous.
Test case (Repeated Parameters): schedule 3 d/2025-04-18 18:00 d/2025-05-17 13:15
or any command with repeated parameter
Expected: Similar to previous.
Test case (Missing Index): schedule d/2025-04-18 18:00
Expected: Similar to previous.
Test case (Invalid Index): schedule x d/2025-04-18 18:00
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test Case (Non-Future DateTime, Invalid DateTime): schedule 3 d/2024-04-10 12:00
, schedule 3 d/2024-04-13 14:00
Expected: Similar to previous.
Test Case (Invalid DateTime): schedule 3 d/2025-02-31 12:00
Expected: Similar to previous.
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure there is an open appointment with the first client and no open appointment with the second client.
Test case: mark 1
Expected: Appointment with the first client is successfully updated as completed. Success message shown in the status message.
Test case (No Open Appointment with existing client): mark 2
Expected: Appointment not updated for any client. Error details in status message.
Test case (Missing Index): mark
Expected: Similar to previous.
Test case (Invalid Index): mark x
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Prerequisites: Nil
Test case: set 45
Expected: Sets the new last met overdue duration to 45 days. Success message shown in the status message.
Test case (Missing Parameters): set
Expected: Last met overdue duration remains unchanged. Error details in status message.
Test Case (Non-numerical, Invalid Parameter): set abc
Expected: Similar to previous.
Test Case (Non-Integer, Invalid Parameter): set 64.6
Expected: Similar to previous.
Test Case (Negative Integer, Invalid Parameter): set -6
Expected: Similar to previous.
Test Case (Value Above Integer Limit): set 1234567890098765432112345564354345324343124134211232132131231
Expected: Similar to previous.
Adding a policy to a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure the first client does not have the policy number "123".
Test case: addpolicy 1 n/Health i/123
Expected: Policy successfully added to first client. Success message shown in the status message.
Test case (Missing Index): addpolicy n/Health i/123
Expected: Policy not added to any client. Error details shown in the status message.
Test case (Missing Parameters): addpolicy 1 n/Health
, addpolicy 1 i/123
or any command with missing parameters
Expected: Similar to previous.
Test case (Invalid Index): addpolicy x n/Health i/123
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test case (Invalid Policy Name): addpolicy 1 n/#Health i/123
Expected: Similar to previous.
Test case (Invalid Policy Number): addpolicy 1 n/Health i/abc
Expected: Similar to previous.
Test case (Repeated Parameters): addpolicy 1 n/Health i/123 n/Health
or any command with repeated parameter
Expected: Similar to previous.
Deleting a policy from a client while all clients are being shown
Prerequisites: List all clients using the list
command. Multiple clients in the client list. Ensure the first client has the policy number "123".
Test case: deletepolicy 1 i/123
Expected: Policy successfully added to first client. Success message shown in the status message.
Test case (Missing Index): deletepolicy i/123
Expected: Policy not added to any client. Error details shown in the status message.
Test case (Missing Parameters): deletepolicy 1
Expected: Similar to previous.
Test case (Invalid Index): deletepolicy x i/123
(where x is smaller or larger than the list size)
Expected: Similar to previous.
Test case (Invalid Policy Number): deletepolicy 1 i/abc
Expected: Similar to previous.
Test case (Repeated Parameters): deletepolicy 1 i/123 i/123
Expected: Similar to previous.
Dealing with missing/corrupted clientcare.json
Prerequisites: The clientcare.json file exists in the data directory.
Test case: Delete the clientcare.json file.
Expected: The app launches successfully, populated with the sample data.
Test case: Delete contents of clientcare.json file.
Expected: The app launches successfully, populated with no data.
Test case: Add random characters to json file that affects the formatting of the file.
Expected: Similar to previous.
Dealing with wrongly edit clientcare.json
Prerequisites: The clientcare.json file exists in the data directory.
Test case: Remove fields from clients.
Expected: The app launches successfully, populated with no data.
Test case: Reorder of fields in client.
Expected: Similar to previous.
Dealing with missing/corrupted setvalue.txt
Prerequisites: The setvalue.txt file exists in the data directory.
Test case: Delete the setvalue.txt file.
Expected: The app launches successfully, with the default overdue period value.
Test case: Empty setvalue.txt file.
Expected: Similar to previous.
Test case: Add non-digit characters to setvalue.txt file.
Expected: Similar to previous.
Test case: Add non-integer values to setvalue.txt file.
Expected: Similar to previous.
Test Case: Add negative integer values to setvalue.txt file.
Expected: Similar to previous.
Dealing with wrongly edit setvalue.txt
Prerequisites: The setvalue.txt file exists in the data directory.
Test case: Edit value to be over integer limit.
Expected: The app launches successfully, with the default overdue period value.
Test case: Add non-digit characters to the file.
Expected: Similar to previous.
Test case: Edit value to be negative.
Expected: Similar to previous.
Test case: Edit value to be non-integer.
Expected: Similar to previous.
Team Size: 4
John
and john
are regarded as different clients. In future versions, names will be case-insensitive./
when adding or editing the client name. In future versions, we will support the use of special characters like /
for names.1. Scheduling Features
Difficulty Level: 3.5/5
Effort Required: 3.5/5
Challenges faced: met
, schedule
, mark
and set
commands help the user manage his scheduling matters. As these 4 commands directly affect each other, the difficulty comes in thinking what and how
their respective class methods should interact with each other, especially with what date format to choose as this directly affects our auto-sort implemented for scheduling. It is also difficult to test for extreme cases that may cause these commands to misbehave.
We decided to simplify the process by restricting the user to 1 appointment per client as our initial beta version faced multiple bugs due to higher number of classes and functions when supporting multiple appointments per client.
To implement the Reminders feature, we had to get the list of clients, so that we are able to filter out the clients that have appointments/ met is overdue/ or have upcoming birthdays, so that we can display them in the reminders panel.
However, the prior implementation in the AddressBook
class of the method getPersonList()
returns an unmodifiable list, which means that we are unable to use that list to get the new list of filtered out the clients that have appointments/ met is overdue/ or have upcoming birthdays.
Thus, we had to create methods within the UniquePersonList
class to get the list of clients that have appointments/ met is overdue/ or have upcoming birthdays, so that we can display them in the reminders panel. Furthermore, we had to sort this new list so that the reminders will be displayed in the correct order.
set
is also saved in a separate txt file as it is not related to client traits. Hence, additional testing is needed to ensure the value that set
updates is saved correctly and is able to handle
invalid values if the txt file is edited wrongly.
2. Policies Features
Difficulty Level: 3.5/5
Effort Required: 3.5/5
Challenged faced: addpolicy
and deletepolicy
commands help the user manage his client's policies. The difficulty comes thinking of how to save the policies into storage and how to retrieve them.
Although Tag
which was already implemented in AB3 was similar and could be used as a reference, the Policy
feature was more complex as it required the saving of 2 different values (policyName
and policy ID
), instead of just 1 in the case of tags, and thus policies cannot be just saved in the same way and have to be parsed differently
Additional testing was needed to ensure that the policies are saved correctly and are able to handle invalid values if the json file is edited wrongly.
As to keep the Person
object immutable, we had to create a new Person
object with the updated policy list when adding or deleting a policy. This made testing for the addpolicy
and deletepolicy
commands more difficult as the addressbook
object prevents us from directly updating the Person
object. Thus, more methods have to be implemented in ModelManger
class to enable proper updating of the expected AddressBook
object when testing.
3. Additional Client Traits and Features
Difficulty Level: 3/5
Effort Required: 3/5
Challenges faced: When implementing sorting of clients, the challenge was understanding the design principles behind how ModelManager#filteredPersons
was implemented in AB3. Since this is an iterative project, we had to ensure that the principles were consistent.
For instance, we recognised that ModelManager#filteredPersons
was an immutable list, and thus our initial implementation of removing the final
keyword from the filteredPersons
field was incorrect and broke the design principles. We had to revert this change and design an alternative solution that adhered to the design principles.
This took some time to understand and implement correctly. Birthday
and Priority
are extensions of the Person
model and required classes of their own. DateUtil
and DateTimeUtil
classes were additionally created to handle dates and times, which was used widely, and thus had to be well-designed to ensure utility and prevent bugs.
Testing for most features were very extensive, with multiple edge cases and invalid inputs. Quality of design was ensured and priorities over shortcut alternatives. For instance, data structures like HashMap
was utilised to map string inputs to PriorityValue
enums. All these quality design required time and effort.
4. GUI
Difficulty Level: 3/5
Effort Required: 3/5
Challenges faced: Some challenges arose in the designing of changes to the GUI to present all the details we wanted. This included the placement of the various panels so that they fit together well without feeling cluttered. There was also considerable time spent on the Reminders panel on the right in particular, as we were not sure at first how we wanted to show all three types of reminders (last met, birthdays, schedules) without overcrowding. Originally, all three were to be shown together in one "Reminders This Week", but we felt that it would be hard to read for the user.
There was also some consideration on how we wanted to handle refreshing the various panels, e.g. viewing the client details as explained in Viewing client feature.