This project is based on the AddressBook-Level3 project created by the SE-EDU initiative.
Generative AI tools such as chatgpt and GitHub Copilot were selectively used to support the development process, specifically for:
The main implementation and logic were independently developed and verified by the project team.
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 deletePerson 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 several parts:
PersonListPanel
with PersonCard
and PreferenceListPanel
with PreferenceCard
ListingListPanel
with ListingCard
and OwnerListPanel
with OwnerCard
TagListPanel
HelpWindow
, StatusBarFooter
All these components, 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("deletePerson 1")
API call as an example.
Note: The lifeline for DeletePersonCommandParser
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., DeletePersonCommandParser
) and uses it to parse the command.Command
object (more precisely, an object of one of its subclasses e.g., DeletePersonCommand
) 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., AddPersonCommandParser
) which uses the other classes shown above to parse the user command and create a XYZCommand
object (e.g., AddPersonCommand
) which the AddressBookParser
returns back as a Command
object.XYZCommandParser
classes (e.g., AddPersonCommandParser
, DeletePersonCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
Note: The attributes of Person
, Tag
, PriceRange
that have been promoted to a class are abstracted into separate class diagrams for ease of reading.
The Model
component,
Person
, PropertyPreference
, Listing
and Tag
and PriceRange
objects.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.PropertyPreference
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<PropertyPreference>
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.Listing
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Listing>
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.Tag
objects (e.g., results of a search query) as a separate filtered set which is exposed to outsiders as an unmodifiable ObservableList<Tag>
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)Person
Person
objects contained in a UniquePersonList
object.Person
may have multiplePropertyPreference
and Listing
associations.Person
is identified their phone number.PropertyPreference
PropertyPreference
may have a PriceRange
, and multiple Tag
associations.Note: A PropertyPreference
can only be tied to 1 Person
to group criterias for a property that they are looking for, under a representative person responsible for the purchase.
Listing
Listing
objects contained in a UniqueListingList
object.Listing
may have a PriceRange
, and multiple Tag
and Owner
associations.Listing
should have either a Unit Number
or a House Number
but not both.Listing
is identified by a combination of the Postal Code
and either the Unit Number
or the House Number
depending on which one is present.Note: A Listing
can have multiple Person
to reflect co-ownership scenarios. Additionally in certain cases joint approval of a listing is required for a purchase.
PriceRange
PriceRange
may have a lower bound price and a upper bound price.PriceRange
is unbounded.Tag
Tag
objects contained in a TagRegistry
object.Tag
may have multiple Listing
and PropertyPreference
associations.Tag
is identified by a string tag name.Note: An possible alternative representation of Tag is to split the tag that stores the association from the tag name, promoting the tag name into a class.
SearchContext
and SearchType
Bidirectional navigability:
Listing
and Person
:
seller
display label. Alternatively a counter could also be used, however a direct reference would better ensure correctness.Person
and PropertyPreference
:
Listing
and Tags
:
PropertyPreference
and Tags
:
API : Storage.java
The Storage
component,
Storage
interface, which inherits from both AddressBookStorage
and UserPrefsStorage
.
This allows it to be used for storing either address book data or user preferences independently.StorageManager
, which delegates to:
JsonAddressBookStorage
— handles storage and retrieval of address book data.JsonUserPrefsStorage
— handles storage and retrieval of user preferences.JsonSerializableAddressBook
as the top-level serializable container to read/write the full address book.JsonAdaptedPerson
, JsonAdaptedListing
, JsonAdaptedTag
,
JsonAdaptedPreference
, and JsonAdaptedPriceRange
) to convert between JSON and model types.ReadOnlyAddressBook
and UserPrefs
, as it handles the persistence of these entities.Note:
In JsonAdaptedListing
, the ownerKeys
field contains phone numbers as strings.
These are used to look up the corresponding Person
objects during deserialization — forming an indirect association from Listing
to Person
.
Classes used by multiple components are in the seedu.address.commons
package.
This section describes how certain proposed features are to be implemented in future iterations.
The proposed undo/redo mechanism is facilitated by VersionedAddressBook
. It extends AddressBook
with an undo/redo history, stored internally as an addressBookStateList
and currentStatePointer
. Additionally, it implements the following operations:
VersionedAddressBook#commit()
— Saves the current address book state in its history.VersionedAddressBook#undo()
— Restores the previous address book state from its history.VersionedAddressBook#redo()
— Restores a previously undone address book state from its history.These operations are exposed in the Model
interface as Model#commitAddressBook()
, Model#undoAddressBook()
and Model#redoAddressBook()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes delete 5
command to delete the 5th person in the address book. The delete
command calls Model#commitAddressBook()
, causing the modified state of the address book after the delete 5
command executes to be saved in the addressBookStateList
, and the currentStatePointer
is shifted to the newly inserted address book state.
Step 3. The user executes add n/David …
to add a new person. The add
command also calls Model#commitAddressBook()
, causing another modified address book state to be saved into the addressBookStateList
.
Note: If a command fails its execution, it will not call Model#commitAddressBook()
, so the address book state will not be saved into the addressBookStateList
.
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undoAddressBook()
, which will shift the currentStatePointer
once to the left, pointing it to the previous address book state, and restores the address book to that state.
Note: If the currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The undo
command uses Model#canUndoAddressBook()
to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
The following sequence diagram shows how an undo operation goes through the Logic
component:
Note: The lifeline for UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Similarly, how an undo operation goes through the Model
component is shown below:
The redo
command does the opposite — it calls Model#redoAddressBook()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the address book to that state.
Note: If the currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest address book state, then there are no undone AddressBook states to restore. The redo
command uses Model#canRedoAddressBook()
to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
Step 5. The user then decides to execute the command list
. Commands that do not modify the address book, such as list
, will usually not call Model#commitAddressBook()
, Model#undoAddressBook()
or Model#redoAddressBook()
. Thus, the addressBookStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitAddressBook()
. Since the currentStatePointer
is not pointing at the end of the addressBookStateList
, all address book states after the currentStatePointer
will be purged. Reason: It no longer makes sense to redo the add n/David …
command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
Aspect: How undo & redo executes:
Alternative 1 (current choice): Saves the entire address book.
Alternative 2: Individual command knows how to undo/redo by itself.
delete
, just save the person being deleted).The edit tag command allows users to edit the name of an existing tag. This command is useful when users want to change the name of a tag that they have already created. The following sequence diagram shows how the edit tag command works:
The associated Listings and PropertyPreferences will be updated to reflect the new tag name.
The edit listing command allows users to edit the details of an existing listing. This command is useful when users want to update information such as postal code, unit/house number, price range, or property name of a listing. The following sequence diagram shows how the edit listing command works:
The edit operation will update the listing's details while maintaining its existing tags, owners and availability status. The system can ensure that no duplicate listings can be created through this command by checking the postal code and unit/house number combination.
The edit preference command allows users to edit the details of an existing preference. This command is useful when users want to update information such as the price range of a preference. The following sequence diagram shows how the edit preference command works:
The associated Person and Tags will be updated to reflect the new preference details.
Note that getters would need to be added to Price Range for this command to work.
The merge tag command allows users to merge an existing tag into another existing tag. This command is useful when users want to merge two similarly named tags. One consideration is to subsume this proposal into the proposed edit tag command, however this results in the possibility of users accidentally merging two distinct tags, when they intended to rename if a tag does not exist. The following sequence diagram shows how the merge tag command works:
The associated Listings and PropertyPreferences from the tag that was merged from will also be merged into the other existing tag.
These are features still in consideration about whether to be implemented.
Issue: Users who are unfamiliar with the command may accidentally delete all their data, as the current clear command deletes everything without any confirmation.
Current implementation: Clear without confirmation.
Alternative 1: Clear with confirmation window pop-up.
Alternative 2: Clear with confirmation command.
logic
sequence diagram by having multiple commands that need to be created and executed.Issue: Experienced users may prefer shorter command words. However, there are multiple variations for shorthands for a word, for example Preference
has the common shorthand of Pref
, Pf
and Pfr
. Thus, using shorthands across the current number of commands may increase the initial learning curve of the application.
Current implementation: Commands not using shorthands.
Alternative 1: Commands using shorthands.
Alternative 2: Rename command.
Issue: Users may intend to search by a space separated keyword “Alex Yeoh” instead of 2 keywords “Alex” and “Yeoh”.
Current implementation: Keywords do not include space.
Alternative 1: Keyword includes space.
Alternative 2: New command format of searchPersonName n/Name…
, for example searchPersonName n/Alex Yeoh n/John Doe
n/
might be more appropriate for such a command.Issue: Users may intend to search person by name and then search person by tags concurrently.
Current implementation: Search overwrites other filters.
Alternative 1: New search does not overwrite previous filters.
Issue: Users may add many tags and scrolling through said list to find a specific tag may be tedious.
Current implementation: No filter.
Alternative 1: SearchTagName command.
Note: A list tag command is already created which should be useful in listing all tags after a searchTagName command, however it is currently disconnected from use by the user.
Profile Tim is a busy, independent real estate agent working in Singapore, managing multiple buyers and sellers simultaneously.
He often communicates with clients through messaging applications and understands their preferences and specifications from chat logs. During client meetups, open houses, and property tours, he may also take notes on common likes and dislikes among clients.
He records these details in an Excel sheet on his laptop, sometimes on the fly, and is highly experienced in fast typing.
Tim has noticed that many client requests can be matched with specific listings he has, but manually filtering and matching these requests with listings can be cumbersome.
Work Patterns
Real estate agents often struggle to manage buyers and sellers through messaging apps. MatchEstate allows tracking of buyers and sellers easily as well as their preferences and offerings respectively. It enables fast matching of buyers and sellers. It is tailored for those who prefer CLIs.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * | potential user | see a list of all available commands on startup | quickly learn how to use the app |
* * | forgetful real estate agent | view a help menu | reference how to use the system effectively |
* * | potential user | have the application come preloaded with sample data | easily try all the commands before adding my real clients |
* * | new user | clear the sample data | populate the application with actual data |
* * | real estate agent | clear all data | reset the system when necessary |
* * * | new user | add my previously accumulated buyer and seller profile information | populate the data in the app with my previously recorded data |
* * * | new user | remove the app's default tags that are created | eventually replace it with my own personalized tags |
* * * | real estate agent | add buyer information | manage my buyers easily |
* * * | real estate agent | add seller information | manage my sellers easily |
* * * | real estate agent | view all clients | easily track the clients I have |
* * | real estate agent | edit a person's details | update their information when needed |
* * * | real estate agent | delete a client | only track relevant clients |
* * | real estate agent | find a client by name | quickly retrieve the details of a specific client |
* * * | real estate agent | add property information | manage my listings easily |
* * * | real estate agent | add a property to a person | track how many properties they are selling |
* * * | real estate agent | add a property to a person | track the property's current seller |
* * * | real estate agent | add the preferences of a person | track what type of properties they are interested in purchasing |
* * * | real estate agent | add more than one property preference | simultaneously track multiple distinct properties a client is interested in purchasing |
* * * | real estate agent | add tags to a property preference | categorize a person's buying interests more effectively |
* * * | real estate agent | remove a tag from a property preference | adjust my information to match a person's interests as they change |
* * | real estate agent | overwrite tags in a property preference | completely update a person's buying criteria as necessary |
* * * | real estate agent | delete a property preference from a person | remove no longer relevant buying interests from the systemy |
* * * | real estate agent | add a property | track the information in the system |
* * * | real estate agent | view all listings | easily track the properties that are listed for sale |
* * * | real estate agent | add tags to a property | categorize the property by its key details |
* * * | careless real estate agent | remove a tag from a property | correct the details if necessary |
* * | careless real estate agent | overwrite tags in a property | completely update its categorization if necessary |
* * * | real estate agent | delete a property | remove no longer relevant listings from the system |
* * * | real estate agent | mark a property as unavailable | ensure that listings that are on hold are no longer considered for matching |
* * | real estate agent | mark a property as available when the listing is no longer on hold | ensure that listings that are no longer on hold can be considered for matching. |
* * | real estate agent | match a person with properties based on the number of common tags and budget | quickly find listings that fit their preferences |
* * | real estate agent | match a property with potential buyers based on the number of common tags and their budget | identify interested persons efficiently. |
* * | real estate agent | filter properties based on a person's preferences | provide targeted property recommendations. |
* * * | real estate agent | add custom tags | customize the categorization of property preferences and properties according to my workflow. |
* * * | real estate agent | add custom tags | capture niche preferences (such as pet-friendly). |
* * * | real estate agent | list all tags | see the available categories in the system. |
* * * | real estate agent | delete a tag | remove outdated and unnecessary categorization from the system. |
* * * | careless real estate agent | delete a tag | remove tags that I have mistakenly added. |
* * | real estate agent | search for properties by tags | quickly find relevant listings. |
* * | real estate agent | search for persons by tags | find buyers based on their property preferences |
* | real estate agent | attach notes to my clients | keep track of specific client requirements beyond common tags |
* * | real estate agent | update my buyer's information when new information is available | ensure that my information remains accurate and up to date |
* * | real estate agent | update my seller's information when new information is available | ensure that my information remains accurate and up to date |
* * | real estate agent | update my listing's information when new information is available | ensure that my information remains accurate and up to date. |
* | inexperienced user | undo accidental deletions or edits | revert mistakes quickly |
* * | real estate agent | filter listings based on price range | focus on properties within the buyer's budget. |
* | real estate agent | be able to list properties that clients have already toured | avoid re-touring them on the same listing by accident. |
* | real estate agent | be able to add properties that the clients liked | keep track of the properties that they are interested in. |
* | independent real estate agent | be able to export a list of buyers | share them with other agents for collaboration. |
* | frequent user | archive buyers and sellers who are inactive | reduce clutter when matching/searching. |
* | efficient user who may not have access to the app at all times | write bulk commands in a text file to add, edit or delete client details at the end of the day | update information without having the application on hand. |
* | real estate agent | view the status of a deal (e.g., Inquiry, Viewing, Offer, Closed) | understand the deal's progression at a glance. |
* | real estate agent | be able to create backups and restore data via CLI commands | do not risk losing client information in the event of data corruption. |
* | real estate agent | be able to view a log of all commands executed | review my past commands. |
* | power user | create custom command aliases (e.g., mb for match --batch) | customize the commands to my workflow and work more efficiently. |
* | real estate agent | store notes for each deal | keep track of important discussions. |
* | real estate agent | create a simple summary of all buyers and listings | use it for basic data analytics purposes and understand my portfolio demographic. |
* | real estate agent | auto-generate templated messages for matched buyers and sellers and export them to WhatsApp/Email | ensure that the process of writing electronic direct mails is simplified. |
(For all use cases below, the System is the MatchEstate
and the Actor is the user
, unless specified otherwise)
MSS
User requests to list persons.
MatchEstate shows a list of persons.
MatchEstate displays a success message.
Use case ends.
Similar to UC01 except for listings instead.
MSS
User requests to list listings.
MatchEstate shows a list of listings.
MatchEstate displays a success message.
Use case ends.
Similar to UC01 except for tags and is always displayed as there is no filter and hence, no user request step is required.
MSS
MatchEstate shows a list of tags.
MatchEstate displays a success message.
Use case ends.
MSS
User requests to list persons(UC01).
User specifies a person to add.
MatchEstate adds the person.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The specified person is invalid.
Use case ends.
2b. The specified person already exists.
2b1. MatchEstate shows an error message.
Use case ends.
MSS
User requests to list listings(UC02).
User requests to list tags(UC03).
User specifies a listing and its associated existing tags and new tags to add.
MatchEstate adds the listing.
MatchEstate creates the new tags specified.
MatchEstate adds the tags to the listing.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The specified listing is invalid.
Use case ends.
3b. The specified listing already exists.
3b1. MatchEstate shows an error message.
Use case ends.
3c. New tags to be created already exist.
Use case ends.
3d. Existing tags specified do not exist.
Use case ends.
4a. No new tags to be created.
Use case resumes at 6.
4b. No existing and new tags specified.
Use case resumes at 8.
Similar to UC04 except for tags instead.
MSS
User requests to list tags(UC03).
User specifies new tags to create.
MatchEstate creates new tags.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The specified tag is invalid.
Use case ends.
2b. New tag to be created already exists.
Use case ends.
MSS
User requests to list persons(UC01).
User requests to list listings(UC02).
User requests to add a specified person to a specified listing.
MatchEstate adds the person to the listing.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The listing index is invalid.
Use case ends.
3c. The listing is already owned by the person.
Use case ends.
Similar to UC05 except listing persons and adding property preference to the specified person. Note that preferences can be duplicates, so there are no extensions for it already existing.
MSS
User requests to list persons(UC01).
User requests to list tags(UC03).
User specifies a property preference with its associated existing tags and new tags to add to a specified person.
MatchEstate adds a new property preference to the person.
MatchEstate creates new tags.
MatchEstate adds the tags to the property preference.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The specified property preference is invalid.
Use case ends.
3c. New tags to be created already exist.
Use case ends.
3d. Existing tags specified do not exist.
Use case ends.
4a. No new tags to be created.
Use case resumes at 6.
4b. No existing and new tags specified.
Use case resumes at 8.
Similar to UC08 but references an existing property preference instead. Note that it throws an error if no existing and new tags are specified.
MSS
User requests to list persons(UC01).
User requests to list tags(UC03).
User requests to add new and existing tags to a property preference.
MatchEstate creates new tags.
MatchEstate adds the tags to the property preference.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The property preference index is invalid.
Use case ends.
3c. New tags to be created already exist.
Use case ends.
3d. Existing tags specified do not exist.
Use case ends.
3e. No new tags to be created.
Use case resumes at 5.
3f. No existing and new tags specified.
Use case ends.
Similar to UC09 but references an existing listing instead.
MSS
User requests to list listings(UC02).
User requests to list tags(UC03).
User requests to add new and existing tags to a listing.
MatchEstate creates new tags.
MatchEstate adds the tags to the listing.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The listing index is invalid.
Use case ends.
3b. New tags to be created already exist.
Use case ends.
3c. Existing tags specified do not exist.
Use case ends.
3d. No new tags to be created.
Use case resumes at 5.
3e. No existing and new tags specified.
Use case ends.
Similar to UC09 but does not create new tags and removes the tags instead.
MSS
User requests to list persons(UC01).
User requests to list tags(UC03).
User requests to delete tags from a property preference.
MatchEstate removes the tags from the property preferences.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The property preference index is invalid.
Use case ends.
3c. Tags specified do not exist.
Use case ends.
3d. No tag specified.
Use case ends.
Similar to UC010 but does not create new tags and removes the tags instead.
MSS
User requests to list listings(UC02).
User requests to list tags(UC03).
User requests to delete tags from a property.
MatchEstate removes the tags from the listing.
MatchEstate updates the usage number of the tags
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The listing index is invalid.
Use case ends.
3b. Tags specified do not exist.
Use case ends
3c. The tag is not present in the property.
Use case ends.
3d. No tags specified.
Use case ends.
Similar to UC07 but removes instead of adds. Note that the owners are displayed with the listing, hence there is no need for UC01.
MSS
User requests to list listings(UC02).
User requests to remove a specified owner from a specified listing.
MatchEstate removes the owner from the listing.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The listing index is invalid.
Use case ends.
2b. The owner index is invalid.
Use case ends.
Similar to UC08 but removes instead of adds. Note that tags are appropriately removed when deleting a property preference, hence there is no need for UC03.
MSS
User requests to list persons(UC01).
User requests to delete a property preference from a person.
MatchEstate updates the usage number of tags used by the person’s property preferences.
MatchEstate removes the property preference from the person.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The person index is invalid.
Use case ends.
2b. The preference index is invalid.
Use case ends.
2c. The property preferences do not have tags.
Use case resumes at 4.
MSS
User requests to list listing(UC02).
User requests to delete a listing.
MatchEstate updates the usage number of tags used by the listing.
MatchEstate updates the listing list of all its owners.
MatchEstate deletes the listing.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The listing index is invalid.
Use case ends.
2b. The listing does not have tags.
Use case resumes at 4.
2c. The listing does not have tags and has no owner.
Use case resumes at 5.
3a. The listing has no owner.
Use case resumes at 5.
MSS
User requests to list persons(UC01).
User requests to delete a person.
MatchEstate updates the usage number of tags used by the person’s property preferences.
MatchEstate deletes the person’s property preferences.
MatchEstate deletes ownership of listing for all of the person’s listings.
MatchEstate deletes the person.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The person index is invalid.
Use case ends.
2b. The person has no property preferences.
Use case resumes at 5.
2c. None of the person's property preferences have tags.
Use case resumes at 4.
2d. The person has no property preferences and has no listings.
Use case resumes at 6.
4a. The person has no listings.
Use case resumes at 6.
MSS
User requests to list tags(UC03).
User requests to delete a tag.
MatchEstate deletes the tag from its property preferences.
MatchEstate deletes the tag from its listings.
MatchEstate deletes the tag.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The tag specified does not exist.
Use case ends.
2b. The tag has no property preferences using it.
Use case resumes at 4.
2c. The tag has no property preferences and listings using it
Use case resumes at 5.
3a. The tag has no listings using it
Use case resumes at 5.
MSS
User requests to list persons(UC01).
User requests to edit a person.
MatchEstate edits the person.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The person index is invalid.
Use case ends.
2b. The specified edited person is invalid.
Use case ends.
2c. The expected edited person already exists.
Use case ends.
MSS
User requests to list listings(UC02).
User specifies a listing to mark as unavailable.
MatchEstate marks the listing as unavailable.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The listing index is invalid.
2a1. MatchEstate shows an error message.
Use case ends.
MSS
User requests to list listings(UC02).
User specifies a listing to mark as available.
MatchEstate marks the listing as available.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The listing index is invalid.
2a1. MatchEstate shows an error message.
Use case ends.
Similar to UC09 and UC011. Note that overwrite is effectively a combination of adding and deleting.
MSS
User requests to list persons(UC01).
User requests to list tags(UC03).
User requests to overwrite the tags of a property preference with new and existing tags.
MatchEstate creates new tags.
MatchEstate removes all tags from the property preference.
MatchEstate adds the tags specified to the property preference.
MatchEstate updates the usage number of the tags.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The property preference index is invalid.
Use case ends.
3c. New tags to be created already exist.
Use case ends.
3d. Existing tags specified do not exist.
Use case ends.
3e. No new tags to be created.
Use case resumes at 5.
3f. No new tags to be created, no existing tags.
Use case ends.
3g. No new tags to be created and property preference has no tags.
Use case resumes at 6.
4a. Property preference has no tags.
Use case resumes at 6.
Similar to UC21 except for listings instead.
MSS
User requests to list listings(UC02).
User requests to list tags(UC03).
User requests to overwrite the tags of a listing with new and existing tags.
MatchEstate creates new tags.
MatchEstate removes all tags from the listing.
MatchEstate adds the tags specified to the listing.
MatchEstate updates the usage number of the tags
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The listing index is invalid.
Use case ends.
3b. New tags to be created already exist.
Use case ends.
3c. Existing tags specified do not exist.
Use case ends.
3d. No new tags to be created.
Use case resumes at 5.
3e. No new tags to be created, no existing tags.
Use case ends.
3f. No new tags to be created and listings have no tags.
Use case resumes at 6.
4a. The listing has no tags.
Use case resumes at 6.
MSS
User requests to list persons(UC01).
User specifies a search criteria containing one or more keywords.
MatchEstate filters the list of persons, displaying only those that contain any of the specified keywords.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The specified keywords is invalid.
Use case ends.
3a. No persons match the specified keywords.
Use case ends.
Similar to UC23 except with a has all tags criteria.
MSS
User requests to list listings(UC02).
User specifies a search criteria containing one or more tags.
MatchEstate filters the list of listings, displaying only those that contain all specified tags.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The tag specified does not exist.
Use case ends.
2b. No tags specified.
Use case ends.
3a. No listings match the specified tags.
Use case ends.
Similar to UC24 except for property preferences.
MSS
User requests to list persons(UC01).
User specifies a search criteria containing one or more tags.
MatchEstate filters the list of persons, displaying only those that contain all specified tags.
MatchEstate displays a success message.
Use case ends.
Extensions
2a. The specified tag does not exist.
Use case ends.
2b. No tags specified.
Use case ends.
3a. No persons match the specified preference tags.
Use case ends.
MSS
User requests to list persons(UC01).
User requests to list listings(UC02).
User specifies the person to search as the owner in the list of listings.
MatchEstate filters the listings, displaying on those with the specified person as an owner.
MatchEstate a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
MSS
User requests to list list persons(UC01).
User requests to list listings (UC02).
User specifies a property preference in a person to find a matching listing.
MatchEstate filters the list of listings, displaying based on if any tags and price range of the available listing not owned by the person matches the property preference.
MatchEstate sorts the filtered listings by the highest number of matching criteria.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The person index is invalid.
Use case ends.
3b. The property preference index is invalid.
Use case ends.
Similar to UC27 except for a listing.
MSS
User requests to list list persons(UC01).
User requests to list list listings(UC02).
User specifies a listing to find a matching property preference across all persons.
MatchEstate filters the list of property preferences, displaying persons who do not own the listing, based on if any tags and price range of their preferences matches the listing.
MatchEstate sorts the filtered persons by the highest number of matching criteria in their preferences.
MatchEstate displays a success message.
Use case ends.
Extensions
3a. The listing index is invalid.
Use case ends.
MSS
User requests to clear all data in the system.
MatchEstate clears all tags, persons, preferences and listings.
MatchEstate displays a success message
Use case ends.
MSS
User requests to view a list of commands.
MatchEstate displays a help window.
MatchEstate displays a success message.
Use case ends.
MSS
User requests to exit MatchEstate.
MatchEstate closes.
Use case ends.
17
or above installed.17
.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the jar file and copy into an empty folder
Double-click the jar file Expected: Shows the GUI with a set of sample persons, tags, listings and property preferences. 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 listing with valid parameters
Prerequisites: There is no existing listings that has the combination of postal code and house number/unit number as any of the listings being added. Also, the tag existingTag
exists and the tag nonExistentTag
does not exist in the system.
Test case: addListing pc/123456 h/100 lbp/300000 ubp/600000 n/Sunny Villa
Expected: Listing is added with postal code, house number, price range and name. Success message shown.
Test case: addListing pc/123456 h/101 n/Sunny Villa
Expected: Listing is added with postal code, house number and name. Success message shown.
Test case: addListing pc/123456 u/10-10 lbp/300000 ubp/600000 n/Sunny Villa
Expected: Listing is added with postal code, unit number, price range and name. Success message shown.
Test case: addListing pc/123456 u/10-11 n/Sunny Villa
Expected: Listing is added with postal code, unit number and name with no price limits. Success message shown.
Test case: addListing pc/123456 u/10-13 ubp/600000 n/Sunny Villa
Expected: Listing is added with postal code, unit number, price range (with no lower limit) and name. Success message shown.
Test case: addListing pc/123456 u/10-14 lbp/600000 n/Sunny Villa
Expected: Listing is added with postal code, unit number, price range (with no upper limit) and name. Success message shown.
Test case: addListing pc/123456 u/10-15 lbp/300000 ubp/6000000 n/Sunny Villa t/existingTag
Expected: Listing is added with postal code, unit number, price range, name and tag. Success message shown.
Test case: addListing pc/123456 u/10-16 lbp/300000 ubp/600000 n/Sunny Villa nt/newTag
Expected: Listing is added with postal code, unit number, price range, name and new tag. Success message shown.
Adding a listing with invalid parameters
Prerequisites: The tag existingTag
exists and the tag nonExistentTag
does not exist in the system. Also, a listing with postal code: 123456 and house number: 100 exists in the system.
Test case: addListing pc/123456
Expected: Error message shown mentioning that either house number or unit number must be provided, but not both.
Test case: addListing u/01-01
Expected: Error message shown about how a postal code must be provided.
Test case: addListing pc/123456 u/01-01 h/123 n/Sunny Villa
Expected: Error message shown mentioning that either house number or unit number must be provided, but not both.
Test case: addListing pc/123456 u/01-01 lbp/600000 ubp/300000
Expected: Error message shown about invalid price range (lower bound > upper bound).
Test case: addListing pc/123456 u/01-01 lbp/300000 ubp/600000 t/nonExistentTag
Expected: Error message shown about invalid tags.
Test case: addListing pc/123456 u/01-01 lbp/300000 ubp/600000 nt/existingTag
Expected: Error message shown about duplicate tags.
Test case: addListing pc/123456 h/100 lbp/300000 ubp/600000 n/Sunny Villa
Expected: Error message shown about duplicate listings.
Deleting a listing with valid parameter
Prerequisites: At least one listing must exist.
Test case: deleteListing 1
Expected: First listing is deleted from the list. Details of the deleted listing shown in the status message.
All associated owners and tags are updated accordingly.
Deleting a listing with invalid commands
Test case: deleteListing 0
Expected: No listing is deleted. Error message shown about index not being a non-zero integer.
Test case: deleteListing x
(where x is larger than the list size)
Expected: No listing is deleted. Error message shown about invalid listing index.
Adding a preference with valid parameters
Prerequisites: At least one person exists in the list. The tag existingTag
exists and the tag nonExistentTag
does not exist.
Test case: addPreference 1 lbp/300000 ubp/600000 t/existingTag nt/nonExistentTag
Expected: Preference is added to the first person with specified price range and tags. Success message shown.
Test case: addPreference 1 lbp/300000 ubp/600000
Expected: Preference is added to the first person with specified price range but no tags. Success message shown.
Test case: addPreference 1 lbp/300000
Expected: Preference is added to the first person with only lower bound price. Success message shown.
Test case: addPreference 1 ubp/600000
Expected: Preference is added to the first person with only upper bound price. Success message shown.
Test case: addPreference 1 t/existingTag
Expected: Preference is added to the first person with tag. Success message shown.
Test case: addPreference 1 nt/nonExistentTag
Expected: Preference is added to the first person with new tag. Success message shown.
Adding a preference with invalid parameters
Prerequisites: At least one person exists in the list. The tag existingTag
exists and the tag nonExistentTag
does not exist in the system.
Test case: addPreference
Expected: Error message shown about missing arguments.
Test case: addPreference 1 lbp/600000 ubp/300000
Expected: Error message shown about invalid price range (lower bound > upper bound).
Test case: addPreference 1 lbp/300000 ubp/600000 t/nonExistentTag
Expected: Error message shown about invalid tags.
Test case: addPreference 1 lbp/300000 ubp/600000 nt/existingTag
Expected: Error message shown about duplicate tags.
Test case: addPreference 0 lbp/300000 ubp/600000
Expected: Error message shown about index not being a non-zero integer.
Test case: addPreference x lbp/300000 ubp/600000
(where x is larger than the list size)
Expected: Error message shown about invalid person index.
Deleting a preference with valid parameters
Prerequisites: At least 2 persons exist in the list, each with at least 3 preferences.
Test case: deletePreference 1 1
Expected: First preference of the first person is deleted. Success message shown.
Test case: deletePreference 2 3
Expected: Third preference of the second person is deleted. Success message shown.
Deleting a preference with invalid parameters
Prerequisites: At least 1 person exists in the list.
Test case: deletePreference 1
Expected: Error message shown about expecting 2 indices to be provided.
Test case: deletePreference 0 1
Expected: Error message shown about index not being a non-zero integer.
Test case: deletePreference 999 1
Expected: Error message shown about invalid person index.
Adding a tag with valid parameters
Prerequisites: The tag nonExistentTag1
, nonExistentTag2
and nonExistentTag3
do not exist in the system.
Test case: addTag nt/nonExistentTag1
Expected: New tag "nonExistentTag1" is added. Success message shown.
Test case: addTag nt/nonExistentTag2 nt/nonExistentTag3
Expected: Both tags "nonExistentTag2" and "nonExistentTag3" are added. Success message shown.
Adding a tag with invalid parameters
Test case: addTag nt/a
Expected: Error message shown about tag name requirements such as length and character limitations.
Test case: addTag nt/this-tag-name-is-way-too-long-to-be-valid
Expected: Error message shown about tag name requirements such as length and character limitations.
Test case: addTag nt/invalid!tag
Expected: Error message shown about tag name requirements such as length and character limitations.
Test case: addTag nt/existingTag
(where "existingTag" already exists)
Expected: Error message shown about duplicate tags.
Deleting a tag with valid parameters
Prerequisites: The tag existingTag1
, existingTag2
and existingTag3
exist in the system.
Test case: deleteTag t/existingTag1
Expected: Tag "existingTag1" is deleted from the system. The listings and property preferences that used "existingTag1" previously are updated accordingly. Success message shown.
Test case: deleteTag t/existingTag2 t/existingTag3
Expected: Both tags "existingTag2" and "existingTag3" are deleted from the system. The listings and property preferences that used "existingTag2" and "existingTag3" previously are updated accordingly. Success message shown.
Deleting a tag with invalid parameters
Test case: deleteTag t/
Expected: Error message shown about tag name requirements such as length and character limitations.
Test case: deleteTag t/this-tag-name-is-way-too-long-to-be-valid
Expected: Error message shown about tag name requirements such as length and character limitations.
Test case: deleteTag t/nonExistentTag
Expected: Error message shown about invalid tag.
Matching a listing with valid parameters
Prerequisites: At least one listing exists in the list and there are persons with property preferences.
Test case: matchListing 1
Expected: The system finds and displays all persons whose property preferences match the first listing.
Persons are sorted by the number of matching criteria (tags and price range).
Persons who own the listing are excluded from the results. Success message shown.
Matching a listing with invalid parameters
Test case: matchListing 0
Expected: Error message shown about index not being a non-zero integer.
Test case: matchListing x
(where x is larger than the list size)
Expected: Error message shown about invalid listing index.