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
and DeleteCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches 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).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)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.
This feature allows users to assign tags to / remove tags from customers in EzContact, making customers more recognizable to the users.
The activity diagram below shows the action sequence of updating the tags of a customer. Note that definition of not valid indexes/tags/tag set will be defined later in following sections.
Tag
Before implementing the actual command execution of tag,
tags first needs to be stored in a Person
object accordingly.
Hence, a Person
will now also be associated to any number of Tag
s.
In order to integrate the command for handling tag features into the execution logic as described in LogicComponent, there are 3 main steps we need to implement:
AddressBookParser
to recognise the tag command word and will create a TagCommandParser
subsequently.
(Modification required is trivial and hence not described in detail)TagCommandParser
class that will parse the command arguments and construct a TagCommand
accordingly.TagCommand
class that will handle the main execution logic of the tag features and return a CommandResult
accordingly.The sequence diagram below illustrates the interactions within the Logic
component when executing a tag command,
taking execute("tag 1 at/tall dt/short at/handsome")
API call to LogicManager
as an example.
Note:
The lifeline for TagCommandParser
and TagCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
TagCommandParser
TagCommandParser
plays the role of parsing command arguments into two information:
Both index and descriptor will then be used to construct a TagCommand
.
Note that duplicate tags will be ignored (see Design Considerations for more information).
The sequence diagram below illustrates the interactions of TagCommandParser#parse(String arguments)
,
taking parse(1 at/tall dt/short at/handsome)
call to the TagCommandParser
as an example.
TagCommand
The following class diagram illustrates how a TagCommand
holds information required for its execution.
TagCommand
plays the role of executing the main logic of the tag feature, it will:
Person
object accordingly.Model
accordingly to reflect the changes.Note that a TagCommand
is non-executable if there are conflicting tags (i.e. there are common tags to add and delete).
The sequence diagram below illustrates the interations of TagCommand#execute(Model model)
,
taking execute(m)
call to the TagCommand
as an example. Note that the reference frames have been omitted
as the operations performed are trivial and low-level details.
As reaching this point, we have completed the implementation of the tag feature. The following section will discuss certain design considerations when implementing this feature.
Set<Tag>
.
Tag
in the Set<Tag>
.List<Tag>
.
Tag
is more complicated.Reasoning :
Alternative 1 was chosen over alternative 2 as the ordering of tags is considered not that important in the case of
storing tags.
Reasoning :
Alternative 1 was chosen over alternative 2 based on the following reasons:
Reasoning:
Alternative 1 was selected over alternative 2 because the primary reason for users deleting a specific tag is that
they wish to prevent the tagged customer from having that tag. Therefore, whether the targeted customer
initially possesses the tag is of lesser importance in this context.
This aspect is similar to the above aspect regarding Deletion of non-existing tags, the current choice is to simply ignore such additions due to the same reason stated above.
This find feature is designed to do partial search or prefix search on the customer list.
Sequence diagram below shows the interactions between Logic
components when executing execute("find n/Song r/vegetarian")
XYZContainsKeywordsPredicate
XYZContainsKeywordsPredicate
= AddressContainsKeywordsPredicate
, NameContainsKeywordsPredicate
etc
This class inherits from Predicate interface and determine how the find
feature searches for the right customers.
It tests each customer in the list with given keywords
(search prompt given by users) in the following way:
The attribute(name/address/...)
will be tested over each keyword
in the search prompt (e.g. "james bond" is broken down into "james" & "bond")
The attribute(name/address/...)
will also be tested word by word for every keyword
in the prompt on these criteria:
attribute
fully matches all the keywords
(e.g. "james bond" = "james bond"), it returns trueattribute
contains all the keywords
(e.g. searches "james" in "james bond"), it returns truekeyword
is prefix of the attribute
(e.g. searches "ja" in "james bond), it returns truePersonContainsKeywordsPredicate
This class serves as the primary predicate for testing multiple conditions. It houses various predicates such as
NameContainsKeywordsPredicate
to check if specific criteria are met.
FindCommandParser
FindCommandParser
processes the input following the 'find' command, parsing it into distinct predicates based on the provided prefixes.
These predicates are then combined to create a PersonContainsKeywordsPredicate
which is used by FincCommand
FindCommand
FindCommand
is executed on the Model
, it will update the Model
accordingly to
reflect the changes after the FindCommand
completes its execution.
Predicate
, PersonContainsKeywordsPredicate
is responsible for testing them."
PersonContainsKeywordsPredicate
which contains different methods to test different attributes against keywords.
Reasoning :
Due to the Open-Closed Principle, we have opted for Alternative 1 to maintain modularity in our codebase.
XYZContainsKeywordsPredicate
regarding prefix:Lam Jiu
from Jiu Lam
, a name can also match with multiple keywords (i.e. name song
match with keywords song song
).song
cannot match with keywords song song
.
Reasoning :
In this case, we chose Alternative 1 over Alternative 2 because the find feature becomes less versatile when we enforce the rule that
the name must match keywords in order. The consideration about our target users being forgetful affects our decision,
where users might forget and input the name in the wrong order.
We also chose Alternative 1 over Alternative 3, although Alternative 3 provides a more accurate result, after doing some research on many contact book-like applications, we found that most applications do not enforce that each word of the name can only match with one keyword. In addition, Alternative 3 requires a more complicated algorithm.
Stream
and use allMatch
.
List<String>
and using a for loop.
Reasoning :
Alternative 1 is chosen over Alternative 2, because we want a slightly simpler design that does not need as much flexibility.
This feature allows users to assign / remove insurance package(s) to / from customers in EzContact to help users keep track of customers' insurances.
The activity diagram below shows the action sequence of updating insurances of a customer.
The implementation of the Insurance feature consists of few parts, distributed across different components :
Insurance
: stores the information about the insuranceInsuranceCommand
: executes the action to assign/remove insuranceInsuranceCommandParser
: parses the command to obtain required informationImplementing Insurance
Insurance
plays the role of storing information about an insurance and to be displayed on the product, as a single unit. It holds only one information, insuranceName
.
Implementing InsuranceCommand
InsuranceCommand
executes its command on the Model
, it will update the Model
accordingly to reflect the changes made by the command on the Model
.
Sequence diagram below shows the execution of InsuranceCommand
.
Implementing InsuranceCommandParser
InsuranceCommandParser
interprets the remaining input after the insurance
command, and parses it into relevant information needed by InsuranceCommand
, which are
Index
and UpdatedPersonInsuranceDescriptor
.
Index
indicates the customer on the list to perform action on.UpdatedPersonInsruanceDescriptor
holds the sets of insurances to add(insurancesToAdd
) and delete(insurancesToDelete
).Sequence diagram below shows the execution of InsuranceCommandParser#parse(String arguments)
with input (1 ai/car insurance\n di/health insurance)
Integrating InsuranceCommand
and InsuranceCommandParser
In order to integrate them into current logic component, AddressBookParser
has to be updated to recognise the command
insurance
and call parse(arguments)
from InsuranceCommandParser
.
From here, InsuranceCommandParser
will extract out the relevant information and create the corresponding InsuranceCommand
and the command will be executed by other Logic
components.
Sequence diagram below shows the interactions between Logic
components when executing execute("insurance 1 \nai/AIA di/Great Eastern)
Insurance
in Person
Set<Insurance>
to hold all Insurance
instances in Person
object
Set<Insurance>
Insurance
inserted is not maintainedList<Insurance>
to hold all Insurance
instances in Person
object
Insurance
inserted and sorting can be easily done on Insurance
instancesReasoning:
Alternative 1 is chosen over Alternative 2 for its ability to handle the duplicates more efficiently. We believe that this ability is more important
than the ability to sort the list in a more effective manner, as there are other workarounds that can be almost as efficient using Set<Insurances>
.
Insurnace
entriesInsurance
as long as no conflict exists (i.e. adding and deleting the same Insurance
)
Insurance
Insurance
Insurance
Reasoning:
Alternative 1 is chosen over Alternative 2 because we believe doing so will provide users a smoother experience with our product.
The reasoning comes from the users' intention of inserting the InsuranceCommand
, that is wanting to assign an Insurance
to a customer, so with
entering duplicate Insurance
, the users' goal is still achieved, thus we think that there is no need to purposely block the users
for such action. With our handling of duplicate Insurance
, no duplicate values will be added into the model with duplicate Insurance
entries, and thus
it will not cause any error.
Insurance
Insurance
as long as no conflict exists (i.e. adding and deleting the same Insurance
)
Insurance
Reasoning:
Alternative 1 is chosen over Alternative 2 because we believe doing so will provide users a smoother experience with our product.
The reasoning comes from the users' intention of deleting an Insurance
, that is wanting to remove that Insurance
from the customer, so removing
a non-existing Insurance
does not defeat the purpose, thus we think that there is no need to purposely block the users
for such action.
The appointment feature supports 4 different types of commands:
addappt
deleteappt
markappt
unmarkappt
All 4 features extends from the abstract
Command
class, managing the details of an apppointment
with a customer by editing the details of the Appointment
and AppointmentCount
class.
Implementing Appointment
This class is used to represent the appointment that each Person
has, containing data:
date
of the appointment in dd-MMM-yyyy
format as a String
time
of the appointment in HHmm
format as a String
venue
of the appointment as a String
lesser than or equals to 30 characters.By default, each Person
has an empty default appointment.
Implementing AppointmentCommand
AppointmentCommand
executes its command on the Model, updating the Model accordingly to reflect the changes made by the command on the Model. Note that an AppointmentCommand
is non-executable if the index is not in range or the person has an existing appointment.
The sequence diagram below illustrates the interactions of AppointmentCommand#execute(Model model)
, taking execute(m)
call to the AppointmentCommand
as an example. Note that the reference frames have been omitted as the operations performed are trivial.
Implementing AppointmentCommandParser
AppointmentCommandParser
plays the role of parsing command arguments into two or more fields:
Both index and date minimally, will then be used to construct an AppointmentCommand.
The sequence diagram below illustrates the interactions of AppointmentCommandParser#parse(String arguments)
, taking parse(1 d/2025-12-12 t/12:55 v/Clementi Mall)
call to the AppointmentCommandParser
as an example.
Integrating AppointmentCommand
and AppointmentCommandParser
AddressBookParser
recognises the command addappt
and calls parse(arguements)
from AppointmentCommandParser
.
AppointmentCommandParser
will extract out the relevant information and create the corresponding AppointmentCommand
which will be executed by other Logic
components.
The sequence diagram below shows the interactions between Logic
components when the user inputs the command
addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall
.
Implementing Addappt
AppointmentCommandParser::parse()
uses ParserUtil::parseDateString()
, ParserUtil::parseTimeString()
to check if date
, time
, venue
follows the required formatting and the new Appointment
object created by AppointmentCommandParser:parse()
.
AppointmentCommand::execute()
checks if the current Appointment
is an empty
appointment and if true
, executes the AppointmentCommand
.
Implementing Deleteappt
Using a similar logic flow as addappt
, it creates a new Appointment
object with empty date
, time
and venue
to replace the existing Appointment
object. The new Appointment
object is created in DeleteAppointmentCommandParser::parse()
.
Deleteappt
prevents the deletion of an appointment if there is no existing appointment by checking if the current Appointment
is different from the empty
appointment and if true
, executes the DeleteAppointmentCommand
.
Implementing AppointmentCount
This class contains the number of marked appointments with a customer, stored as count
, the
number of completed appointments as an int
.
Implementing Mark Appointment
Using a similar logic flow as addappt
, it checks if the current Appointment
is different from the empty
appointment and if true
, MarkAppointmentCommand::execute()
will use AppointmentCount::incrementAppointmentCount()
to increase the count by 1.
The existing Appointment
object will be replaced by a new empty Appointment
object, created in MarkAppointmentCommandParser::parse()
.
Implementing Unmarkappt
Using a similar logic flow as addappt
, it prevents the user from unmarking an appointment if there is an existing
appointment by checking if the current Appointment
is the same as the empty
appointment and if true
,
UnmarkAppointmentCommand::execute()
will use AppointmentCount::DecrementAppointmentCount()
to decrease the count by 1.
This feature allows users to assign priority to a Person
.
The default priority of each Person
is NONE
, unless a priority is explicitly assigned to the Person
.
The activity diagram below shows the sequence of actions when users assign a priority to a Person
.
The Priority
class
The class is used to store the priority level of a Person
.
The priority level can only be one of the values in the Level
enumeration.
Each Person
now has an additional attribute called priority.
The Person
class now has a reference to the Priority
class.
Adding a new command word priority
To allow users to assign priorities, we added a new command word priority
.
The sequence diagram shows a series of actions in EzContact when a user inputs the command priority 1 high
.
Note:
The lifeline for PriorityCommandParser
and PriorityCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The PriorityCommandParser
class
The class is used to parse the string provided.
It will return a PriorityCommand
if the index and priority are valid.
The sequence diagram below illustrates the interaction between PriorityCommandParser
and PriorityCommand
when PriorityCommandParser#parse(String)
is invoked.
Taking parse("1 high")
as an example.
The sequence diagram below illustrates how the index and priority are parsed.
The PriorityCommand
class
The class diagram below shows the main attributes and methods involved when assigning a priority to a Person
.
The sequence diagram illustrates the execution of the PriorityCommand
and how the Person
is updated.
Person
without an explicitly assigned Priority
.Person
a default priority NONE
.
Person
has null
priority.null
.
null
cases to handle.HIGH
, MEDIUM
, LOW
and NONE
. (NONE
is chosen when user removes or does not assign a priority).
The action of assigning a remark is mainly facilitated by three classes: Remark
, RemarkCommandParser
and RemarkCommand
.
The Remark
class
This class represents a person's attribute, including a remark string with a maximum length of 150 characters. Every person created has this attribute, with the default value being an empty string, signifying no remark.
The RemarkCommandParser
class
The class is used to parse the arguments into two information: index
and remark
and
returns a RemarkCommand
if the arguments are valid.
The sequence diagram below illustrates the interaction between RemarkCommandParser
, RemarkCommand
and Remark
.
Taking parse("2 he likes pizza")
as an example.
The RemarkCommand
class
The class is responsible in executing the task parsed by the RemarkCommandParser
.
It will update the Remark
of a Person
and generate a CommandResult
for the output.
Below is the class diagram of the RemarkCommand
class.
Remark
remark <index>
without argument.
Reasoning:
In real-life scenarios, storing empty strings as remark is unlikely, hence alternative 1 is preferred due to its user-friendliness.
Target user profile:
Target user : Insurance agent
Value proposition:
Manage customers' contact for existing/potential insurance contracts faster than GUI driven apps, alongside helping users increase the chance of sealing deals with customers.
Priorities: High - * * *
, Medium - * *
, Low - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | user | be able to add new contacts to EzContact | keep track of my contacts using EzContact |
* * * | user | be able to update my contacts' information easily | easily maintain up-to-date information of my contacts |
* * * | user | be able to search for specific contacts using their names | quickly lookup a contact and get their information |
* * * | user | be able to delete contacts | |
* * * | user | be able to list out my contacts in EzContact | see all my saved contacts in one view |
* * * | insurance agent | be able to add customers' contacts to EzContact | reach out to existing and potential customers easily |
* * * | insurance agent | be able to assign priorities to each customer | prioritise customers that have a higher chance on sealing a deal |
* * * | insurance agent | be able to view the type of insurance my customer currently holds | check customers' insurance profile easily |
* * * | insurance agent | be able to easily know customers subscribed under a specific insurance plan | quickly know who to find when there are changes to a specific insurance plan |
* * * | insurance agent | be able to apply descriptive tags to my customers | easily identify and remember my customers using these tag |
* * * | insurance agent | be able to add details of appointments with customers | keep track of appointments with customers |
* * * | insurance agent | be able to delete cancelled appointments with customers | prevent confusion when arranging my schedule |
* * * | insurance agent | be able to mark completed appointments with customers | keep track of appointments completed with the customer to guage their potential interest |
* * | user | be able to search for a contact using its other particulars(not necessarily names) | be more flexible when searching for contacts |
* * | user | be able to see my total numbers of contact entries in EzContact | know how many contacts I have in EzContact |
* * | forgetful person | be able to search for contacts using partial names | find a contact without having to remember their full name |
* * | forgetful person | have EzContact remind me of important task associated with certain contacts | prevent myself from forgetting important tasks |
* * | forgetful person | be able to add remarks to a certain contact | be reminded of things to take note of when contacting a person |
* * | careless person | be able to undo previous command | recover from unintentional commands |
* * | careless person | be stopped from adding duplicate entries | avoid myself from adding redundant data |
* * | careless person | be suggested by EzContact for similar names when I'm searching for a person | avoid myself from typographical errors |
* * | first time user | be able to know commands in EzContact | play around with the features and get used to the application |
* * | fast typist | have short commands | execute commands faster |
* | user | be able to import my data from external sources into EzContact | avoid myself from having to copy my data manually |
* | user | be able to export my data | have a backup of data in case of data loss |
* | advanced user | have multiple contact books | neatly organize my contacts based on contexts |
(For all use cases below, the System is the EzContact
and the Actor is the User
, unless specified otherwise)
Use Case: UC01 - add a customer
MSS:
1. User provides the details of a customer to be added.
2. EzContact displays the details of the customer added by User.
Use case ends.
Extensions:
1a. Details provided by User is incomplete or invalid.
1a1. EzContact displays an error message to alert User.
Use case ends.
1b. Customer to be added is already in the EzContact.
1b1. EzContact displays an error message to alert User.
Use case ends.
Use case: UC02 - filter customers
MSS:
1. User chooses to filter customers.
2. User selectively adds one/multiple category parameters to filter the customers for.
3. EzContact displays the list of customers that meet the criteria.
Use case ends.
Extensions:
2a. User doesn't select any categories to filter for.
2a1. EzContact displays the entire list of customers.
Use case ends.
3a. None of the contacts meet the filter criteria.
3a1. EzContact shows an empty list with a warning message.
Use case ends.
Use Case: UC03 - delete a customer
MSS:
1. User requests a list of customers by filtering customers(UC02).
2. User provides the index of customer to be deleted.
3. EzContact displays the details of the removed customer.
Use case ends.
Extensions:
2a. User provides invalid index.
2a1. EzContact shows an error message to alert User.
Use case ends.
Use Case: UC04 - edit a customer's details
MSS:
1. User requests a list of customers by filtering customers(UC02).
2. User provides information to the customer with its respective index.
3. EzContact displays the details of the edited customer.
Use case ends.
Extensions:
2a. User provides invalid index or information.
2a1. EzContact shows an error message to alert User.
Use case ends.
Use Case: UC05 - search for a customer
MSS:
1. User searches with a prompt.
2. EzContact shows a list of customers matching the prompt.
3. User views the customers' information.
Use case ends.
Extensions:
1a. User searches with an invalid prompt format
1a1. EzContact shows an error message to User.
Use case ends.
2a. There is no customer that match the prompt.
2a1. EzContact shows an empty list.
Use case ends.
Use Case: UC06 - assign priority to a customer
MSS:
1. User requests a list of customers by filtering customers(UC02).
2. User provides priority to the customer with its respective index.
3. EzContact displays the new priority of customer.
Use case ends.
Extensions:
2a. User provides invalid index or priority.
2a1. EzContact shows an error message to alert User about the invalid command.
Use case ends.
Use Case: UC07 - assign insurance to a customer
MSS:
1. User requests the list of customers by filtering customers(UCO2).
2. User assigns insurance to the customer with its respective index.
3. EzContact displays the new insurance of customer.
Use case ends.
Extensions:
2a. User provides invalid index or information.
2a1. EzContact shows an error message to alert User about the invalid command.
Use case ends.
Use Case: UC08 - remove insurance from a customer
MSS:
1. User requests the list of customers by filtering customers(UCO2).
2. User removes insurance from the customer with its respective index.
3. EzContact displays the new insurance of customer.
Use case ends.
Extensions:
2a. User provides invalid index or information.
2a1. EzContact shows an error message to alert User about the invalid command.
Use case ends.
Use Case: UC09 - update tags of a customer
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User provides index of the targeted customer in the displayed list.
3. User provides information of tags to add to and/or delete from the targeted customer.
4. EzContact displays the details of the updated customer to the User.
Use case ends.
Extensions:
1a. Requested list is empty.
Use case ends.
2a. User provided invalid index.
2a1. EzContact displays an error message to alert the User.
Use case ends.
3a. User provided invalid information of tags.
3a1. EzContact displays an error message to alert the User.
Use case ends.
3b. User provided information of tags that will not update the targeted customer.
3b1. EzContact displays an error message to alert the User.
Use case ends.
Use Case: UC10 - update remark of a customer
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User enters index and remark of the target customer.
3. EzContact updates the remark of specified customer accordingly.
4. EzContact displays the details of the updated customer.
Use case ends.
Extensions:
2a. User provided invalid index or information.
2a1. EzContact displays an error message to alert the User.
Use case ends.
2b. User provided remark that will not update the specified customer.
2b1. EzContact displays an error message to alert the User.
Use case ends.
Use Case: UC11 - add an appointment to a customer
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User enters index and appointment details(date, time, venue) of the target customer.
3. EzContact adds the appointment to the specified customer accordingly.
4. EzContact displays the updated appointment details of the customer.
Use case ends.
Extensions:
2a. User provided invalid index.
2a1. EzContact displays an error message to alert the User.
Use case ends.
2b. User provided invalid appointment input parameters.
2b1. EzContact shows an error message of the input constraints.
Use case ends.
2c. An appointment has already been scheduled.
2c1. EzContact shows an error message to alert the User.
Use case ends.
Use Case: UC12 - delete a customer's appointment
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User enters index of the target customer.
3. EzContact deletes the appointment of the specified customer accordingly.
4. EzContact displays the updated empty appointment details of the customer.
Use case ends.
Extensions:
2a. User provided invalid index.
2a1. EzContact displays an error message to alert the User.
Use case ends.
2b. There is no existing appointment to delete.
2b1. EzContact shows an error message to alert the User.
Use case ends.
Use Case: UC13 - mark a customer's appointment
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User enters index of the target customer.
3. EzContact marks the appointment of the specified customer accordingly.
4. EzContact displays the updated appointment details of the customer.
Use case ends.
Extensions:
2a. User provided invalid index.
2a1. EzContact displays an error message to alert the User.
Use case ends.
2b. There is no existing appointment to mark.
2c1. EzContact shows an error message to alert the User.
Use case ends.
Use Case: UC14 - unmark a customer's appointment
Mss:
1. User requests a list of customers by filtering customers(UC02).
2. User enters index of the target customer.
3. EzContact unmarks the appointment of the specified customer accordingly.
4. EzContact displays the updated appointment details of the customer.
Use case ends.
Extensions:
2a. User provided invalid index.
2a1. EzContact displays an error message to alert the User.
Use case ends.
2b. There is an existing appointment.
2b1. EzContact shows an error message to alert the User.
Use case ends.
11
or above installed.tag
is the command word of the command tag 1 at/tall dt/short
)1 at/tall dt/short
is the command arguments of the command tag 1 at/tall dt/short
)This section covers the enhancements we plan to implement in the future.
Feature flaw:
As a customer might have many tags, and they could potentially want to remove all the
tags in one command, they would have to type out all the tags separately in order to achieve that.
Proposed enhancement:
We provide a convenient way for users to delete all the tags in one command by adding an optional parameter
to the command. The updated command format would be as follows:
tag <index> [at/<tags to add>]... [dt/<tags to add>]... [dat/deleteall]
.
Justifications:
dat/
prefix to indicate
their interest in deleting all tags, and deleteall
value to the prefix to serve as a confirmation of this
destructive command.Updated behaviours (original behaviours of tag still hold):
dat/
prefix is supplied, there should not be any at/
or dt/
prefix supplied in the same command, if there
is, a format error message will be shown to the user.dat/
is not deleteall
, show an error message to users, indicating that
they should supply the deleteall
value to dat/
in order to confirm the deletion.Examples:
tag 1 dat/deleteall
Expected: All the tags of customer at index 1 is deleted, a successfully deleted all tags
message is shown to user.
tag 1 at/tall dat/deleteall
Expected: Error, an error message showing the usage of tag command is shown to the user.
tag 1 dat/delete
Expected: Error, an error message informing the user that they should input deleteall
to confirm the deletion of all tags
is shown to the user.
Feature flaw:
Users will not be able to easily update or modify appointment details if there are any changes or mistakes. If the appointment meeting location changes, or the scheduled time needs adjustment—without the ability to edit, users would have to delete and create a new appointment, potentially leading to confusion and decreased efficiency.
Proposed enhancement:
We provide a convenient way for users to edit the appointment details, date, time and venue, in a edit appointment command.The updated command format would be as follows:
editappt <index> [d/<date>] [t/time] [v/venue]
Justifications:
Updated behaviours (original behaviours of appointment still hold):
editappt
are the same as the current appointment, there will be a error message to the user that there is no change.Examples:
editappt 1 d/2026-12-16
Expected: Edits the date of the first customer's appointment in the displayed list to be 16 Dec 2026, if it is different at first.
editappt 1
Expected: Error, an error message informing the user to provide at least 1 appointment detail field to be changed.
Feature flaw:
After marking an appointment, the appointment details gets removed. However, after unmarking the appointment, the appointment details do not come back. This might cause the user to need to manually create the appointment meeting again, which can be a hassle, decreasing efficiency.
Proposed enhancement:
The unmark appointment unmarkappt
will not only decrement the appointments completed counter by 1, but also restore the "marked" appointment details.
Updated behaviours (original behaviours of appointment still hold):
Examples:
unmarkappt 1
clear
pops out a confirmation windowFeature flaw:
After the user inputs the clear
command, the customer list is cleared immediately. In some situations where the user just type clear
in accident, the consequence is undesirable.
Proposed enhancement:
Pop a confirmation window for users to confirm once again if the user indeed wants to clear the customer list.
Feature flaw:
The current implementation employs a single prefix for multiple keywords in the find feature, such as find i/Health Auto.
This approach, however, lacks the ability to distinguish between distinct sets of keywords, leading to potential ambiguity.
For instance, it becomes challenging to differentiate whether the keywords correspond to a combination like Health Auto
or separate entities like Health Insurance
and Auto Coverage
.
Proposed enhancement:
To address this limitation, it is recommended to enable the use of multiple identical prefixes for individual keywords. For instance, the enhanced syntax could be find i/Health i/Auto
.
This modification allows the find feature to accommodate duplicate prefixes for both find and tag operations, thereby providing a more precise and unambiguous search capability.
Justifications:
Examples:
find i/abc i/apple
abc
and apple
respectively.
For instance, if there are customer with insurances named abc insurance
and apple insurance
, they would be included in the results.find i/abc apple
abc apple
, such as abc apple insurance
.The enhanced feature ensures accurate and targeted search results.
Feature flaw:
In add
and edit
command, when entering <phone number>
under p/
, it takes in the 8 digits (Singaporean number) with no spaces or -
(e.g. 12345678
).
However, it does not allow other common formats for Singaporean number that includes space and -
(e.g. 1234-5678
, 1234 5678
), which can be a hassle to
users for not being allowed to so.
Proposed enhancement:
Allow <phone number>
with format of 1234 5678
and 1234-5678
Updated behaviours (original behaviour of /p
still holds):
<phone number>
can now take the format of 1234-5678
and 1234 5678
and display the information in EzContactExamples:
edit 1 p/1234-5678
Expected: Update the <phone number>
of customer at index 1 to 1234-5678
edit 1 p/1234 5678
Expected: Update the <phone number>
of customer at index 1 to 1234 5678
Feature flaw:
Currently, duplicated customer is defined as customers that have either identical <email>
or <phone number>
, given that each customer
should have their respective contact details. However, this does not take into consideration that some customers might not have email (e.g. elderly)
and would have others to handle their incoming emails.
Proposed enhancement:
Modify the implementation on checking for duplicate customer such that it accepts identical <email>
exist in EzContact, and update the
error message to This phone number already exists in the contact book
instead of the original duplicate customer message to give users
more accurate feedback on what went wrong.
Justification:
The purpose of EzContact is to help our users (i.e. insurance agent) to manage contacts of customers that he needs to approach / interact with
thus the most important value our product has to offer, is to keep track of and contact customers effectively. Thus, we need to make sure that
each customer is contactable, leading to us enforcing the uniqueness of <phone number>
. <email>
is allowed to have duplicates because it is
possible and common for people to share <email>
(especially elderly who have no email). <name>
is also allowed because it is common to have
identical name. These restrictions give the users maximum flexibility and functionality while still ensuring that each customer is contactable.
Updated behaviours:
<phone number>
are not allowed, error will be thrown indicating that the <phone number>
already existsp/
) already exist in the contact book are allowed.Examples:
add n/joshua p/12345678 e/abc@gmail.com
, add n/james p/78945612 /abc@gmail.com
Expected : Add james
successfully into the contact book with no erroradd n/joshua p/12345678 e/abc@gmail.com
, add n/james p/12345678 /defg@gmail.com
Expected : Error message is thrown indicating that the 12345678
already exist in the contact bookFeature flaw:
With current implementation, when a customer has multiple insurances assigned to he/she, deleting all insurances requires the user to list out
all the insurances with di/
prefix in our insurance
command, which is inconvenient
Proposed enhancement:
Add a new optional prefix dai/
and parameter deleteall
for insurance
command to indicate deleting all insurances,
the new command takes the format of
insurance <index> [ai/<insurance to add>]... [di/<insurance to delete>]... [dai/deleteall]
Justification:
Given that dai/
will remove all the insurances of the customer at once, we require users to do a confirmation by specifying deleteall
for dai/
to ensure that the user execute this command intentionally.
Updated behaviours (Original behaviour of insurance
still holds) :
dai/
is supplied, ai/
and di/
are not allowed. Format error will appear if either prefixes are useddai/
is supplied, if the value supplied to it is not deleteall
, an error message will be thrown, indicating that deleteall
has to be supplied to confirm the deletionExamples:
insurance 2 dai/deleteall
Expected : All insurances of customer at index 2 are removedinsurance 2 dai/deleteall ai/AIA di/cars
Expected : Error message is thrown, showing the usage of insuranceinsurance 2 dai/dvsdv
Expected : Error message is thrown, telling users that deleteall
has to be supplied to confirm deletion.This section gives an overview of the challenges, we as a team faced and the effort we have put in to make this project work.
* * *
With the implementation of various new features in EzContact, the logic
component who’s responsible for the parsing and
handling of our commands
have to go through various modifications and enhancements to fulfill the needs of these features.
The new logic
component needs to be more flexible regarding its constraint on the user input and also need to accommodate
the newly defined commands
by us for the new features
Effort:
The enhancement can be broken down into a few parts:
ArgumentTokenizer
CommandParser
& AddressBookParser
Command
ArgumentTokenizer
has to be understood thoroughly before putting our hands on the codebase.
Along the way, we have had multiple discussions on the choice of prefixes and restriction to put on the prefix input. Upon finalizing
the prefixes and constraints, work is split among members and each take up some part to work on.CommandParser
and AddressBookParser
, we each implement the parser associated with the features we are implementing. We also
integrate our parsers with AddressBookParser
as it parses the command word and determines the CommandParser
to use for remaining of
the command.Commands
are also implemented separately according to the features we are assigned to implement. We ensure that our implementation
does not break the Liskov Substitution Principle since all commands
we implemented inherited the Commmand
class. We also ensure that
our implementation integrates well with each other and does not break others' functionality.
Result :
Our new logic
component now accommodates multiple new features that drastically improve users experience and previous features are also
refined to provide users more flexibility and functionality.
* *
The UI
first has to be redesigned from the perspective of the purpose it serves. We have to ensure that all usages have to be accounted
in the new UI
to ensure that users will always have a clear view of what's going on.
Effort:
We first redesign the structure of our UI
to fit the new features in a sensible and user-friendly way. We tried out different layouts
and ways to present our data, and finalize on the current design, where the customer's information are displayed as Customer Card
. After ensuring
the functionality is covered by UI
, we move on to changing the colour scheme of our product. After many trial and error, and requesting feedbacks
from our friends, we have decided to use the current pastel green colour scheme.
Result :
A newly designed UI
for EzContact and improved UI component with increased usability.
* * *
Given the newly introduced attributes
in EzContact, the storage
component is required to accommodate these new data when creating
the save file.
Effort:
Given that our saving system is implemented using Jackson (JSON package)
, we first have to understand how the package works and how
it is integrated into our system. For each new attribute
, we have created the corresponding JSON-friendly data class
to handle these
data during saving. These classes handle the conversion between application-used and JSON-compatible data during loading and saving.
These classes are integrated to the existing storage
component carefully to ensure that we do not break the existing system. The original
storage
component is also refined and fixed of all discovered bugs.
Result :
A refined storage
component that is able to handle all new attributes
safely and correctly.
* *
To accommodate the new features and attributes
, the model
component now has to handle these new commands
and process these new attributes
.
Effort:
New classes are created to represent and abstract these data to a higher level for easy manipulation. These classes are then integrated into
the Person
class as it is the over-arching class represents the customer. New methods are also added to model
component to perform the execution
specified by the different commands
. We are implementing the respective classes corresponding to the features we are responsible for. The implementations
are done in small increment and are tested along the way.
Result :
A comprehensive model that holds and operates on our customer data according to the command given by logic component.
Given below are instructions to test the app manually.
Scenario
Prerequisite : [condition needed to be fulfilled to perform the action if applicable]
value
result
{ more test cases … }
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Adding a customer to the contact book
Prerequisites: -
Test case: add n/Joshua p/1234-5678 e/opqr@gmail.com
Expected: Customer of name Joshua
with the above details is added
Test case: add n/Joshua p/1234-5678 e/opqr@gmail.com a/1A Kent Ridge Rd t/morning person
Expected: Customer of name Joshua
with the above details is added
Test case: add n/Joshua
Expected: No customer is added. Error message is thrown indicating that compulsory field p/
and e/
are missing
Test case: add n/Joshua p/acaf e/abcdeg@gmail.com
Expected: No customer is added. Error message is thrown indicating that <phone number>
format is incorrect
Test case: add
Expected: No customer is added. Error message is thrown indicating format for add
command is wrong
Deleting a customer while all customers are being shown
Prerequisites: List all customers using the list
command. Multiple customers in the list.
Test case: delete 1
Expected: First customer is deleted from the list. Details of the deleted customer shown in the status message.
Test case: delete 0
Expected: No customer is deleted. Error details shown in the status message. Customer list remains the same.
Other incorrect delete commands to try: delete
, delete x
, ...
(where x is larger than the list size)
Expected: No customer is deleted. Error details shown in the status message. Customer list remains the same.
Updating the tags of a specific customer
Prerequisite : -
Test case : tag 1 at/tall at/fat dt/short dt/skinny
Expected : The tags assigned to the customer at index 1 will be updated accordingly(adds tall
and fat
tag, deletes short
and skinny
tag).
Test case : tag 0 at/tall
Expected : Error, details shown in the status message(format error since the index is not a positive integer).
Test case : tag 1
Expected : Error, details shown in the status message(format error since no tag to update is provided).
Test case: tag 1 at/tall dt/tall
Expected : Error, details shown in the status message(conflicting tags).
Test case: tag 1 dt/dsajdkl
, the tag to delete does not exist in cutomer 1
Expected: Error, details shown in the status message(customer not updated).
Updating the insurances of a customer
Prerequisite : -
Test case : insurance 2 ai/AIA ai/cars di/health di/ABC
Expected : Customer is updated, health
and ABC
insurance are removed and AIA
and cars
insurance are added
Test case : insurance 0 ai/AIA ai/cars di/health di/ABC
``
Expected : Customer is not updated. Error details shown in the status message (format error since the index is not a positive integer).
Test case : insur 3 ai/EFG ai/JFK
Expected : Customer is not updated. Error details shown in the status message (Incorrect command word).
Test case : insurance 4 ai/ABC di/ABC
Expected : Customer is not updated. Error details shown in the status message (conflicting changes).
Test case : insurance 1
Expected : No customer is updated. Error details shown in the status message(format error since no insurances to update is provided).
Find customers
Prerequisite : -
Test case : find n/
Expected : Show all customers in the list, because every customer must has a name.
Test case : find n/a
Expected : Show all customers has a as a prefix in their name.
Test case : find i/ABC t/male
Expected : Show all customers has ABC matches with their insurances and has male matches with their tags.
Test case : find 123
Expected : Customer list not updated. Error details shown in the status message (format error, one prefix must be provided).
Updating the remark of a customer
Prerequisite : -
Test case : remark 2 he don't like pizza
Expected : Customer is updated. Customer's remark update to he don't like pizza
.
Test case : remark 2
``
Expected : Customer is updated. Customer's remark is deleted.
Test case : remark
Expected : Customer is not updated. Error details shown in the status message (No index provided).
Updating the priority of a specific customer
Prerequisite : -
Test case : priority 1 low
Expected : Priority of customer at index 1 is updated to low
.
Test case : priority 1 low
, old priority of customer at index 1 is also low
Expected : Error, details shown in the status message (person is not changed).
Test case : priority 0
Expected : Error, details shown in the status message (format error since the index is not a positive integer).
Test case : priority 1
Expected : Error, details shown in the status message (format error since no priority is provided).
Test case: priority 1 -
Expected : Priority of customer at index 1 is removed (and set to NONE
), no priority label is shown in the Ui.
Updating the appointment of a specific customer
Prerequisite : -
Test case : addappt 1 d/2025-12-12
Expected : Appointment of customer at index 1 is updated to 12 Dec 2025 with empty time and venue.
Test case : addappt 1 d/2025-12-12
, customer at index 1 has existing appointment
Expected : Error, details shown in the status message(appointment is not added).
Test case : deleteappt 1
, customer at index 1 has existing appointment
Expected : Appointment of customer at index 1 is deleted, updated to become an empty appointment.
Test case : deleteappt 1
, customer at index 1 does not have an existing appointment
Expected : Error, details shown in the status message(no appointment).
Test case : markappt 1
, customer at index 1 has an existing appointment
Expected : Appointment of customer at index 1 is deleted, updated to become an empty appointment, and the appointments
completed counter is incremented by 1.
Test case : markappt 1
, customer at index 1 does not have an existing appointment
Expected : Error, details shown in the status message(No appointment exists to be marked).
Test case : markappt 1
, customer at index 1 does not have existing appointment
Expected : Appointments completed counter of customer at index 1 is deceremented by 1.
Test case : umarkappt 1
, customer at index 1 has an existing appointment
Expected : Error, details shown in the status message(cannot be undone if no completed appointment).
Editing the information of a specific customer
Prerequisite : -
Test case : edit 1 n/John
Expected : Name of customer at index 1 is updated to John
.
Test case : edit 0
Expected : Error, details shown in the status message (format error since the index is not a positive integer).
Test case : edit 1
Expected : Error, details shown in the status message (format error since no information is provided).
Test case: edit 1 pr/high
Expected : Error, details shown in status message (priority is not allowed to be edited using the edit command).