Acknowledgements


Setting up, getting started

Refer to the guide Setting up and getting started.


Design

:bulb: Tip: The .puml files used to create diagrams are in this document docs/diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.

Architecture

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.

  • At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
  • At shut down, it shuts down the other components and invokes cleanup methods where necessary.

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 i/1.

Each of the four main components (also shown in the diagram above),

  • defines its API in an interface with the same name as the Component.
  • implements its functionality using a concrete {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.

UI component

The API of this component is specified in Ui.java

Structure of the UI Component

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,

  • executes user commands using the Logic component.
  • listens for changes to Model data so that the UI can be updated with the modified data.
  • keeps a reference to the Logic component, because the UI relies on the Logic to execute commands.
  • depends on some classes in the Model component, as it displays Person object residing in the Model.

Logic component

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 i/1") API call as an example.

Interactions Inside the Logic Component for the `delete i/1` Command

:information_source: Note: The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.

How the Logic component works:

  1. When Logic is called upon to execute a command, LogicManager passes the user input to AddressBookParser.
  2. AddressBookParser identifies the command word and delegates to the corresponding parser (e.g., DeleteCommandParser) to construct a Command object.
  3. LogicManager executes the command against the Model.
  4. If the command is undoable (command.isUndoable()), LogicManager pushes it to an internal undo history stack.
  5. If the command is undo, LogicManager handles it directly by invoking undo(model) on the most recent undoable command in that history stack. More details on the undo feature are provided in the Current Undo feature section under Implementation.
  6. After command execution, LogicManager persists changes through Storage, then returns a CommandResult to the caller.

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 routes each command to an XYZCommandParser (XYZ is a placeholder for the specific command name, e.g., AddCommandParser) that validates input and creates an XYZCommand object.
  • Commands with no parameters (list, clear, exit, undo) are validated directly in AddressBookParser; any extra arguments are rejected.
  • Most command parsers use ArgumentTokenizer and ParserUtil helpers to enforce:
    • required/optional prefixes,
    • duplicate-prefix checks for single-valued fields,
    • detection of invalid or unexpected prefixes,
    • command-specific constraints (e.g., exactly one of i/ or e/ for delete).
  • All XYZCommandParser classes implement the Parser interface so that they can be treated similarly where possible e.g, during testing.

Model component

API : Model.java

The Model component,

  • stores the address book data i.e., all Person objects (which are contained in a UniquePersonList object).
  • A person is considered a duplicate if another person already has the same email, or the same Telegram handle ignoring case.
  • stores the currently ‘selected’ 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.
  • stores a UserPref object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref object.
  • does not depend on any of the other three components (as the Model represents data entities of the domain, they should make sense on their own without depending on other components)
:information_source: Note: An alternative (arguably, a more OOP) model is given below. It has a Tag list in the AddressBook, which Person references. This allows AddressBook to only require one Tag object per unique tag, instead of each Person needing their own Tag objects.

Storage component

API : Storage.java

The Storage component,

  • can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
  • inherits from both AddressBookStorage and UserPrefsStorage, which means it can be treated as either one (if only the functionality of only one is needed).
  • depends on some classes in the Model component (because the Storage component’s job is to save/retrieve objects that belong to the Model)

Adapter pattern for JSON serialization

The Storage component uses an adapter pattern to bridge between the domain model and JSON representation. Three adapter classes handle the conversion:

  • JsonSerializableAddressBook — wraps the entire address book for serialization; its toModelType() method converts back to a ReadOnlyAddressBook, checking for duplicate persons in the process.
  • JsonAdaptedPerson — represents a single Person in JSON form. The fields phone and telegramHandle are optional (nullable); name and email are required. toModelType() validates each field and throws IllegalValueException if any value is invalid.
  • JsonAdaptedTag — represents a single Tag, storing both tagName and tagType.

JSON data format

Data is stored in two JSON files:

  • data/addressbook.json — contact list:
    {
      "addressbook": {
        "persons": [
          {
            "name": "Alex Yeoh",
            "phone": "87438807",
            "email": "alexyeoh@example.com",
            "telegramHandle": "alexyeoh",
            "tags": [{ "tagName": "cs2103t", "tagType": "COURSE" }]
          }
        ]
      }
    }
    
  • preferences.json — GUI window size/position and the address book file path:
    {
      "guiSettings": { "windowWidth": 740.0, "windowHeight": 574.0, "windowCoordinates": { "x": 100, "y": 100 } },
      "addressBookFilePath": "data/addressbook.json"
    }
    

Error handling on startup

When CampusBridge starts, it attempts to read the address book file and handles three cases:

  • File not found — sample data is loaded and the file is created on the next save or exit.
  • File is malformed or contains invalid data — an empty address book is used and a warning is logged; the corrupted file is left untouched.
  • File is valid — data is loaded normally.

Common classes

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


Implementation

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

Add feature

Implementation

The add command is implemented using AddCommandParser and AddCommand.

When the user enters an add command, AddressBookParser delegates the input to AddCommandParser. AddCommandParser tokenizes the input using only the prefixes supported by add: n/, e/, p/, and h/.

The parser enforces the following rules:

  • n/NAME and e/EMAIL are compulsory.
  • p/PHONE and h/TELEGRAM_HANDLE are optional.
  • Values are trimmed before validation.
  • Repeated single-valued prefixes are rejected.
  • Any non-empty preamble is rejected.
  • Known prefixes belonging to other commands, such as t/, tr/, tc/, tg/, i/, o/, and r/, are treated as unexpected extra input in an add command.

After tokenization, AddCommandParser uses ParserUtil to validate and convert each supplied value into the corresponding model type. It then constructs a Person object and returns an AddCommand.

The sequence diagram below illustrates the interactions within the Logic component for a typical successful add command.

Interactions Inside the Logic Component for the `add n/John e/john@gmail.com` Command

When AddCommand executes, it first checks for duplicate conflicts using model.getDuplicateConflict(toAdd). If a duplicate email, duplicate Telegram handle, or both are detected, the command fails. Otherwise, the person is added to the model and a CommandResult is returned. If the added person’s email is not an NUS-domain email, the success message also includes a warning.

AddCommand is undoable. Undoing an add removes the previously added person, unless that person no longer exists in the model.

Duplicate detection

Duplicate detection for add is based on Person#isSamePerson(...).

Two persons are considered the same person if they have:

  • the same email, or
  • the same non-null Telegram handle.

This identity rule is used by UniquePersonList when adding and updating persons. As a result, the add command rejects contacts that duplicate either an existing email or an existing Telegram handle.

Current Undo feature

Current Implementation

Currently, the undo feature is implemented using the Command pattern, where each undoable command encapsulates its own undo logic. The overall undo process is managed by LogicManager.

When an undoable command is executed, it is added to an internal stack (undoHistory : Deque<Command>) maintained by LogicManager.

When the undo command is invoked, LogicManager retrieves the most recent command from undoHistory using peek(). The undo(Model) method of that command is then executed to revert its effects. If the undo operation is successful, the command is removed from the stack using pop().

This design ensures that each command is responsible for reversing its own changes, providing flexibility and adhering to the Command pattern.

The following sequence diagram illustrates how the undo operation is executed:

UndoSequenceDiagram-Logic

The following class diagram shows the structure of the undo feature:

UndoClassDiagram

The following Activity diagram illustrates the control flow of command execution in the undo feature.

UndoActivityDiagram.png

Note: Undo methods in commands directly interact with the Model to revert changes. Hence, we are not having an object diagram here. UI and Storage components are omitted from the diagrams as they are not directly involved in the undo mechanism.

Design considerations:

Aspect: How undo & redo executes:

  • Alternative 1 : Saves the entire address book.
    • Pros: Easy to implement.
    • Cons: May have performance issues in terms of memory usage.
  • Alternative 2 (current choice): Individual command knows how to undo by itself.
    • Pros: Will use less memory (e.g. for delete, just save the person being deleted).
    • Cons: We must ensure that the implementation of each individual command are correct.

{more aspects and alternatives to be added}

[Proposed] Data archiving

{Explain here how the data archiving feature will be implemented}


Documentation, logging, testing, configuration, dev-ops


Appendix: Requirements

Product scope

Target user profile: NUS undergraduate students who

  • Need to organize contact information of their Professors, Teaching Assistants and Groupmates.
  • Values efficiency and prefers tools that save time and reduce friction.
  • Prefer using CLI over GUI.

Value proposition: CampusBridge helps NUS undergraduate students to organize and access contact information for their academic peers across different modules and faculties.

It does so by providing a centralized, easy-to-use system to save, search, and manage academic contacts efficiently.

User stories

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

Current version

Priority As a …​ I can …​ So that I can…​
* * * user add a contact store and organize important academic contact information in one place
* * * user view all my contacts quickly see everyone in one place
* * * user delete a contact keep my contact list accurate and organized
* * * user edit a specific contact quickly correct mistakes in their contact information
* * * user exit the application safely close CampusBridge when I am done using it
* * * user have my contacts saved automatically prevent losing my data when the application closes
* * * user validate my input minimize incorrect information
* * * new user see clear error messages understand what went wrong and correct my input without feeling confused
* * * regular user search contacts by name, email and tags quickly find someone
* * * new user view help details see specific examples and parameter requirements for that command
* * regular user sort contacts by name, email, or phone in ascending or descending order browse them more easily
* * new user view preloaded sample modules and contacts understand the app’s layout and value without adding real data
* * user add new tags to an existing contact keep their information updated as the semester evolves
* * user delete specific tags from a contact without deleting the entire contact keep my contact information accurate
* * user clear all tags from a contact reset the contact’s categorization without manually deleting every individual tag
* * expert user undo my last action instantly revert an accidental deletion without stress
* * expert user have keyboard shortcuts operate the system efficiently
* * expert user copy any contact field efficiently transfer information to other applications without manual typing
* * expert user view colour-coded tags quickly identify and prioritize important information.
* * regular user navigate command history execute or modify past commands without retyping them

Near-future version

Priority As a …​ I can …​ So that I can…​
* user export contact data in a human-readable format like JSON can edit it easily
* regular user mark a preferred contact method know the fastest way to reach someone
* regular user mark certain contacts as favorites keep my most important connections easily accessible at the top of my list
* frequent user add notes to contacts store useful contextual information
* fast typing user use short aliases for commands minimize keystrokes
* forgetful student see a list of “Available Now” contacts based on their office hours know exactly who I want to visit for a walk-in consultation
* regular user create a personal profile tailor the application experience to my specific preferences and needs
* user view a list of command history recall what I just changed
* advanced user bulk add contacts at once save time when entering many contacts
* advanced user bulk delete contacts at once remove outdated or unnecessary contacts efficiently
* advanced user bulk edit contacts at once manage large contact groups with minimal effort
* user managing multiple semesters toggle between “current semester” and “past semesters” views reference old contacts without cluttering my main screen
* user desiring full control customize the GUI theme personalize my experience
* regular user create “sub-groups” for teammates within a module manage project-specific communication efficiently
* frequent user set custom reminders for prof/TA office hours stay on top of opportunities for academic help
* new user import my existing contacts avoid manually adding them
* user with many past contacts archive old semester contacts have my active list remain uncluttered and focused on current needs
* user add my current semester’s modules by searching NUS module codes categorize contacts accurately and save time

See the full list on GitHub

Use cases

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

Use Case: UC01 - Getting Help

Preconditions: Application is running

MSS:

  1. User requests for help.
  2. CampusBridge displays the relevant section of the user guide.

Extension:

  • 1a. User provides an unrecognised command name.
    • 1a1. CampusBridge shows an error listing all valid commands. Use case ends.
  • 1b. User provides more than one word.
    • 1b1. CampusBridge shows an invalid command format error. Use case ends.

Use case ends.

Use Case: UC02 - Add a contact

Preconditions: Application is running

MSS:

  1. User requests to add a contact.
  2. User provides the contact details.
  3. CampusBridge validates the input.
  4. CampusBridge adds the contact and updates the contact list.
  5. CampusBridge shows a success message.

Use case ends.

Extension:

  • 3a. Input does not follow the specified format.
    • 3a1. CampusBridge shows an error message indicating the invalid format.
    • 3a2. CampusBridge requests the user to re-enter input.
    • 3a3. User enters a new input.

    Steps 3a1 - 3a3 are repeated until input is valid. Use case resumes at step 4.

  • 3b. Email or Telegram handle already exists in the contact list.
    • 3b1. CampusBridge shows a failure message indicating that the contact already exists.

    Use case ends.

  • 4a. Contact cannot be added.
    • 4a1. CampusBridge shows an error message indicating the contact could not be added.

    Use case ends.

  • 4b. Storage file cannot be written or accessed.
    • 4b1. CampusBridge shows an error message indicating the contact list could not be saved.

    Use case ends.

Use Case: UC03 - Edit a contact

Preconditions: Application is running and the user has added a contact.

MSS:

  1. User requests to list contacts (UC04).
  2. User requests to edit a contact in the list.
  3. User provides new contact details for that contact.
  4. CampusBridge validates the input.
  5. CampusBridge edits the contact and updates the contact list.
  6. CampusBridge shows a success message.

Use case ends.

Extension:

  • 4a. Target contact identifier does not exist.
    • 4a1. CampusBridge shows an error message indicating the contact does not exist.

    Use case ends.

  • 4b. Input does not follow the specified format.
    • 4b1. CampusBridge shows an error message indicating the invalid format.
    • 4b2. CampusBridge requests the user to re-enter input.
    • 4b3. User enters a new input.

    Steps 4b1 - 4b3 are repeated until input is valid. Use case resumes at step 5.

  • 5a. Contact cannot be updated.
    • 5a1. CampusBridge shows an error message indicating the contact could not be updated.

    Use case ends.

  • 5b. Storage file cannot be written or accessed.
    • 5b1. CampusBridge shows an error message indicating the contact list could not be saved.

    Use case ends.

Use Case: UC04 - Delete a contact

Preconditions: Application is running and the user has added a contact.

MSS:

  1. User requests to list contacts (UC04).
  2. User requests to delete a contact in the list.
  3. CampusBridge validates the input.
  4. CampusBridge deletes the contact and updates the contact list.
  5. CampusBridge shows a success message.

Use case ends.

Extensions:

  • 3a. Target contact identifier does not exist.
    • 3a1. CampusBridge shows an error message indicating the contact does not exist.

    Use case ends.

  • 3b. Input does not follow the specified format.
    • 3b1. CampusBridge shows an error message indicating the invalid format.
    • 3b2. CampusBridge requests the user to re-enter input.
    • 3b3. User enters a new input.

    Steps 3b1 - 3b3 are repeated until input is valid. Use case resumes at step 4.

  • 4a. Contact cannot be deleted.
    • 4a1. CampusBridge shows an error message indicating the contact could not be deleted.

    Use case ends.

  • 4b. Storage file cannot be written or accessed.
    • 4b1. CampusBridge shows an error message indicating the contact list could not be saved.

    Use case ends.

Use Case: UC05 - Add a tag to an existing contact

Preconditions: Application is running and the user has added a contact.

MSS:

  1. User requests to tag a contact in the list.
  2. User provides tag details for that contact.
  3. CampusBridge validates the input.
  4. CampusBridge adds the tag and updates the contact list.
  5. CampusBridge shows a success message.

Use case ends.

Extensions:

  • 3a. Target contact identifier does not exist.
    • 3a1. CampusBridge shows an error message indicating the contact does not exist.

    Use case ends.

  • 3b. Input does not follow the specified format.
    • 3b1. CampusBridge shows an error message indicating the invalid format.
    • 3b2. CampusBridge requests the user to re-enter input.
    • 3b3. User enters a new input.

    Steps 3b1 - 3b3 are repeated until input is valid. Use case resumes at step 4.

  • 3c. Tag already exists for contact.
    • 3c1. CampusBridge informs user that the contact already has this tag.

    Use case ends.

  • 4a. Tag cannot be added.
    • 4a1. CampusBridge shows an error message indicating the tag could not be added.

    Use case ends.

  • 4b. Storage file cannot be written or accessed.
    • 4b1. CampusBridge shows an error message indicating the contact list could not be saved.

    Use case ends.

Use Case: UC06 - Remove a Tag from a Contact

Preconditions: Application is running

MSS:

  1. User requests to remove one or more tags from a contact.
  2. CampusBridge removes the specified tags and displays the updated contact.

Use case ends.

Extensions:

  • 1a. Input does not follow the specified format.
    • 1a1. CampusBridge shows an invalid command format error.

    Use case ends.

  • 1b. Specified contact does not exist.
    • 1b1. CampusBridge shows an error indicating the contact does not exist.

    Use case ends.

  • 1c. None of the specified tags exist on the contact.
    • 1c1. CampusBridge shows an error indicating none of the tags were found.

    Use case ends.

  • 2a. Some but not all specified tags exist on the contact.
    • 2a1. CampusBridge removes the existing tags and displays the updated contact.
    • 2a2. CampusBridge informs the user which tags were not found.

    Use case ends.

Use Case: UC07 - Clearing all tags of a type from a contact

Preconditions: Application is running

MSS:

  1. User requests to list contacts (UC08).
  2. User requests to clear tags of a specific type.
  3. CampusBridge clears all the tags of the specific type and updates the contact list.
  4. CampusBridge shows a success message.

Use case ends.

Extensions:

  • 2a. Target contact identifier does not exist.
    • 2a1. CampusBridge shows an error message indicating the contact does not exist.

    Use case ends.

  • 2b. Input does not follow the specified format.
    • 2b1. CampusBridge shows an error message indicating the invalid format.
    • 2b2. CampusBridge requests the user to re-enter input.
    • 2b3. User enters a new input.

    Steps 2b1 - 2b3 are repeated until input is valid. Use case resumes at step 3.

  • 2c. No tags of specified type exist.
    • 2c1. CampusBridge shows an error indicating no tags found to clear.

    Use case ends.

  • 3a. Storage file cannot be written or accessed.
    • 3a1. CampusBridge shows an error message indicating the contact list could not be saved.

    Use case ends.

Use Case: UC08 - Listing All Contacts

Preconditions: Application is running

MSS:

  1. User requests to list all contacts.
  2. CampusBridge shows a list of all contacts.

Use case ends.

Extensions:

  • 1a. User provides extra arguments.
    • 1a1. CampusBridge shows an invalid command format error.

    Use case ends.

Use Case: UC09 - Sorting contacts

Preconditions: Application is running

MSS:

  1. User requests to sort contacts.
  2. User provides sort field (name/email/phone/reset) and optional reverse order.
  3. CampusBridge validates the input.
  4. CampusBridge sorts the contacts based on the specified criteria.
  5. CampusBridge displays the list of contacts in the specified sorted order.

Use case ends.

Extensions:

  • 3a. Input does not follow the specified format.
    • 3a1. CampusBridge shows an invalid command format error.

    Use case ends.

Use Case: UC10 - Search contacts

Preconditions: Application is running

MSS:

  1. User requests to search for contacts.
  2. User provides the search details.
  3. CampusBridge validates the input.
  4. CampusBridge shows the contacts matching the search query.

Use case ends.

Extensions:

  • 3a. Input does not follow the specified format.
    • 3a1. CampusBridge shows an error message indicating the invalid format.
    • 3a2. CampusBridge requests the user to re-enter input.
    • 3a3. User enters a new input.

    Steps 3a1 - 3a3 are repeated until input is valid. Use case resumes at step 4.

  • 4a. No contacts exist in the list.
    • 4a1. CampusBridge informs the user that no contacts match the search query.

    Use case ends.

Use Case: UC11 - Undo previous action

Preconditions: Application is running

MSS:

  1. User requests to undo the most recent action.
  2. CampusBridge retrieves the most recent undoable command from the undo history.
  3. CampusBridge invokes the undo operation of that command.
  4. The command reverses its own effects on the application state.
  5. CampusBridge updates the undo history.
  6. CampusBridge shows the updated state and a success message.

Use case ends.

Extensions:

  • 2a. No undoable commands available in undo history.
    • 2a1. CampusBridge shows an error message indicating that there are no actions to undo.

    Use case ends.

  • 3a. Command fails to execute its undo operation.
    • 3a1. CampusBridge shows an error message indicating that the undo operation failed.

    Use case ends.

  • 5a. Storage file cannot be written or accessed.
    • 5a1. CampusBridge shows an error message indicating the state could not be saved.

    Use case ends.

Use Case: UC12 - Navigating Command History

Preconditions: Application is running

MSS:

  1. User requests to navigate to an earlier command.
  2. CampusBridge displays the earlier command. Steps 1-2 are repeated until the user is satisfied.

Use case ends.

Extensions:

  • 1a. No command history exists.
    • 1a1. CampusBridge does nothing.

    Use case ends.

  • 2a. User requests to navigate to a more recent command.
    • 2a1. CampusBridge displays the more recent command.

    Use case resumes at step 1.

  • 2b. No earlier command exists.
    • 2b1. CampusBridge does nothing.

    Use case resumes at step 1.

  • 2c. No more recent command exists.
    • 2c1. CampusBridge does nothing.

    Use case resumes at step 1.

Use Case: UC13 - Clearing all contacts

Preconditions: Application is running

MSS:

  1. User requests to clear all contacts.
  2. CampusBridge clears all contacts.

Use case ends.

Extensions:

  • 1a. User provides extra arguments.
    • 1a1. CampusBridge shows an invalid command format error.

    Use case ends.

Use Case: UC14 - Exiting

Preconditions: Application is running

MSS:

  1. User requests to exit the app.
  2. CampusBridge terminates.

Use case ends.

Extensions:

  • 1a. User provides extra arguments.
    • 1a1. CampusBridge shows an invalid command format error.

    Use case ends.

Use case ends.

Non-Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 17 or above installed.
  2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
  3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
  4. Changes should be implemented incrementally, i.e. in a way that allows the app to be usable after each increment, even if some features are not yet implemented.
  5. All logics and storage should be implemented locally, to ensure testability and usability in secure environments without internet access.
  6. The distributed JAR file should not be bloated, preferably less than 10MB, to ensure that it can be easily downloaded and stored on devices with limited storage.

Glossary

  • Mainstream OS: Windows, Linux, Unix, MacOS
  • Private contact detail: A contact detail that is not meant to be shared with others

Appendix: Instructions for manual testing

Given below are instructions to test the app manually.

:information_source: Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

Launch and shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by running java -jar campusbridge.jar in the terminal.

      Expected: The most recent window size and location is retained.

  3. Shutting down

    1. Test case: exit
      Expected: The application closes.

    2. Alternative: Press F3 (or Fn + F3 on Mac).
      Expected: Same as above.

    3. Test case: exit 123
      Expected: Application does not close. Error details shown indicating command does not take in any parameter.

Viewing help

  1. Opening general help

    1. Test case: help
      Expected: The User Guide opens in the system default browser. Status message shows Opened user guide in browser.

    2. Alternative: Press F1 (or Fn + F1 on Mac).
      Expected: Same as above.

  2. Opening command-specific help

    1. Test case: help add
      Expected: The User Guide opens in the system default browser at the add command section. Status message shows Opening user guide for 'add' command.

    2. Other valid command names to try: help list, help edit, help delete, help find, help sort, help tag, help untag, help cleartag, help clear, help exit
      Expected: The User Guide opens at the respective command section. Status message names the command.

  3. Invalid help arguments

    1. Test case: help INVALID
      Expected: The User Guide does not open. Error details shown in the status message.

    2. Test case: help ADD (uppercase)
      Expected: Same as above. Command names are case-sensitive and must be lowercase.

    3. Test case: help add extra
      Expected: Same as above. Only a single command name is accepted; extra words cause a format error.

Adding a person

  1. Adding a person with all fields

    1. Prerequisites: Start with the sample data loaded. Ensure the email and Telegram handle used below do not already exist.

    2. Test case: add n/John Doe e/johndoe@example.com p/91234567 h/john_doe
      Expected: A new contact is added to the list. The success message shows the added person’s details.

  2. Adding a person with only compulsory fields

    1. Prerequisites: Ensure the email used below does not already exist.

    2. Test case: add n/Jane Doe e/janedoe@example.com
      Expected: A new contact is added without phone number and Telegram handle. The success message shows the added person’s details.

  3. Adding a person with a non-NUS email

    1. Prerequisites: Ensure the email used below does not already exist.

    2. Test case: add n/Alex Tan e/alextan@gmail.com
      Expected: A new contact is added. A warning is shown indicating that the email is not an NUS domain.

  4. Adding a person with duplicate email or Telegram handle

    1. Prerequisites: Add a contact using add n/Test Person e/testperson@example.com h/test_person.

    2. Test case: add n/Another Person e/testperson@example.com
      Expected: No person is added. Error details shown in the status message indicating that a person with this email already exists.

    3. Test case: add n/Another Person e/anotherperson@example.com h/test_person
      Expected: No person is added. Error details shown in the status message indicating that a person with this Telegram handle already exists.

    4. Test case: add n/Case Person e/caseperson@example.com h/TEST_PERSON
      Expected: No person is added. Error details shown in the status message indicating that a person with this Telegram handle already exists.

    5. Test case: add n/Another Person e/testperson@example.com h/test_person
      Expected: No person is added. Error details shown in the status message indicating that a person with this email and Telegram handle already exists.

  5. Invalid add commands

    1. Test case: add n/John Doe
      Expected: No person is added. Error details shown in the status message.

    2. Test case: add e/johndoe@example.com
      Expected: No person is added. Error details shown in the status message.

    3. Test case: add n/John Doe e/invalid-email
      Expected: No person is added. Error details shown in the status message.

    4. Test case: add n/John Doe n/Jane Doe e/johndoe@example.com
      Expected: No person is added. Error details shown in the status message indicating duplicate prefixes.

    5. Test case: add n/John Doe e/johndoe@example.com tg/friend
      Expected: No person is added. Error details shown in the status message indicating unexpected extra input.

Editing a person

  1. Editing a person with all fields
    1. Prerequisites: Start with the sample data loaded. Ensure the email and Telegram handle used below do not already exist. At least one person in the list.

    2. Test case: edit 1 n/John Lim e/johnlim@nus.edu.sg p/81234567 h/john_LIM
      Expected: The first contact is updated with the new details. The success message shows the edited person’s details.

  2. Editing a person with one field
    1. Prerequisites: Start with the sample data loaded. Ensure the email and Telegram handle used below do not already exist. At least one person in the list.

    2. Test case: edit 1 n/John Lim
      Expected: The first contact’s name is updated. All other fields remain unchanged. The success message shows the edited person’s details.

    3. Test case: edit 1 e/johnlim@u.nus.edu
      Expected: The first contact’s email is updated. All other fields remain unchanged. The success message shows the edited person’s details.

    4. Test case: edit 1 p/12345678
      Expected: The first contact’s phone number is updated. All other fields remain unchanged. The success message shows the edited person’s details.

    5. Test case: edit 1 h/johnlimm
      Expected: The first contact’s telegram handle is updated. All other fields remain unchanged. The success message shows the edited person’s details.

  3. Editing a person with a non-NUS email
    1. Prerequisites: Start with the sample data loaded. Ensure the email used below do not already exist. At least one person in the list.

    2. Test case: edit 1 e/john@gmail.com
      Expected: The first contact’s email is updated. A warning is shown indicating that the email is not an NUS domain.

  4. Editing a person with duplicate email or Telegram handle
    1. Prerequisites: Start with the sample data loaded. The first contact has email johnlim@u.nus.edu and Telegram handle johnlimm. At least two person in the list.

    2. Test case: edit 2 e/johnlim@u.nus.edu
      Expected: No changes made. Error details shown indicating a person with this email already exists.

    3. Test case: edit 2 h/johnlimm
      Expected: No changes made. Error details shown indicating a person with this Telegram handle already exists.

  5. Invalid edit commands
    1. Test case: edit
      Expected: No changes made. Invalid command format error shown.

    2. Test case: edit 1
      Expected: No changes made. Invalid command format error shown.

    3. Test case: edit 0 n/John Lim
      Expected: No changes made. Error details shown indicating the index should be a positive integer.

    4. Test case: edit 999 n/John Lim (where 999 is larger than list size)
      Expected: No changes made. Error details shown in the status message indicating no person exists at that index and tip to use list command.

    5. Test case: edit 1 n/John Lim n/Jane Lim
      Expected: No changes made. Error details shown indicating duplicate prefixes.

    6. Test case: edit 1 n/John Lim tg/friend
      Expected: No changes made. Error details shown indicating unexpected extra input.

Deleting a person

  1. Deleting a person by index

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: delete i/1
      Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message.

  2. Deleting a person by email

    1. Prerequisites: Ensure a person with email alicetan@u.nus.edu exists in the address book.

    2. Test case: delete e/alicetan@u.nus.edu
      Expected: Person with the specified email is deleted from the list. Details of the deleted contact shown in the status message.

  3. Invalid delete commands

    1. Test case: delete
      Expected: No person deleted. Error details shown in the status message indicating invalid command format and command usage.

    2. Test case: delete i/0
      Expected: No person deleted. Error details shown in the status message indicating index must be a positive integer (1, 2, 3…).

    3. Test case: delete e/invalid-email
      Expected: No person deleted. Error details shown in the status message indicating email constraints.

    4. Test case: delete 1 (missing prefix)
      Expected: No person deleted. Error details shown in the status message indicating invalid command format and command usage.

    5. Test case: delete i/1 i/2(multiple same prefixes)
      Expected: No person deleted. Error details shown in the status message indicating multiple values specified for the following single-valued field(s): i/.

    6. Test case: delete e/alicetan@u.nus.edu i/1 (both prefixes)
      Expected: No person deleted. Error details shown in the status message indicating invalid command format and command usage.

    7. Test case: delete i/1 n/alice p/12345678 (multiple invalid prefixes)
      Expected: No person deleted. Error details shown in the status message invalid command format and unexpected extra input.

    8. Test case: delete i/100 (where 100 is larger than list size)
      Expected: No person deleted. Error details shown in the status message indicating no person exists at that index and tip to use list command.

    9. Test case: delete e/nonexistent@example.com
      Expected: No person deleted. Error details shown in the status message indicating no person found with that email and tip to use list or find commands.

Tagging a person

  1. Adding tags to a person

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first and second person has no existing tags.

    2. Test case: tag 1 tg/friends
      Expected: friends general tag is added to the 1st person in the list. Status message shows the details of the new tags added.

    3. Test case: tag 2 tg/groupmates tc/cs2103
      Expected: Both groupmates general tag and cs2103 course tag are added to the 2nd person in the list. Status message shows the details of the new tags added.

    4. Test case: tag 2 tr/tutor tr/TUTOR (duplicate with different case)
      Expected: Only one tutor role tag is added to the 2nd person in the list. Status message shows the details of the new tags added.

    5. Test case: tag 2 tr/mentor tg/mentor (same name, different types)
      Expected: Both mentor tutor tag and mentor general tag are added to the 2nd person in the list. Status message shows the details of the new tags added.

  2. Adding tags to a person where some tags already exist

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first person only have existing friends general tag and cs2103 course tag.

    2. Test case: tag 1 tg/friends tg/groupmates (where friends already exists)
      Expected: Only groupmates general tag is added to the 1st person in the list. Status message shows:
      New tags added: [GENERAL: groupmates]
      Tags already existing (no changes made): [GENERAL: friends]
      
    3. Test case: tag 1 tc/cs2109s tc/cs2100 tc/cs2103 (where cs2103 already exists)
      Expected: cs2109s and cs2100 course tags are added to the 1st person in the list. Status message shows:
      New tags added: [COURSE: cs2109s, COURSE: cs2100]
      Tags already existing (no changes made): [COURSE: cs2103]
      
  3. Adding tags to a person where all tags already exist

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first person have existing friends general tag and cs2103 course tag.

    2. Test case: tag 1 tg/friends (where friends already exists)
      Expected: No changes made. Error details shown in the status message indicating that all tags already exist for this person and no changes made.

    3. Test case: tag 1 tg/friends tc/cs2103 (where both tags already exists)
      Expected: No changes made. Error details shown in the status message indicating that all tags already exist for this person and no changes made.

  4. Invalid tag commands

    1. Test case: tag
      Expected: No tag added. Error details shown in the status message indicating invalid command format and command usage.

    2. Test case: tag 0
      Expected: No tag added. Error details shown in the status message indicating index must be a positive integer (1, 2, 3…).

    3. Test case: tag 1 test (missing prefix)
      Expected: No tag added. Error details shown in the status message indicating invalid command format and command usage.

    4. Test case: tag 1 n/alice (invalid prefixes)
      Expected: No tag added. Error details shown in the status message indicating invalid command format and unexpected extra input.

    5. Test case: tag 1 tr/ (missing value)
      Expected: No tag added. Error details shown in the status message indicating invalid command format and empty value provided for prefix.

    6. Test case: tag 100 tg/friends (where 100 is larger than list size)
      Expected: No tag added. Error details shown in the status message indicating no person exists at that index and tip to use list command.

    7. Test case: tag 1 tr/tutor space
      Expected: No tag added. Error details shown in the status message indicating tags names should be alphanumeric only (no spaces or special characters).

Untagging a person

  1. Removing tags from a person

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first person have existing tutor role tag, cs2103 course tag, friends and groupmates general tags.

    2. Test case: untag 1 tg/friends
      Expected: friends general tag is removed from the 1st person in the list. Status message shows the details of the tags removed.

    3. Test case: untag 1 tg/groupmates tc/cs2103
      Expected: Both groupmates general tag and cs2103 course tag are removed from the 1st person in the list. Status message shows the details of the tags removed.

    4. Test case: untag 1 tr/tutor tr/TUTOR (duplicate with different case)
      Expected: Only one tutor role tag is removed from the 1st person in the list. Status message shows the details of the tags removed.

  2. Removing tags from a person where some tags don’t exist

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first person only have existing cs2103 course tag and friends general tags.

    2. Test case: untag 1 tg/friends tr/tutor (where friends exists but tutor doesn’t)
      Expected: Only friends general tag is removed from the 1st person in the list. Status message shows:
      Tags removed: [GENERAL: friends]
      Tags not found: [ROLE: tutor]
      
    3. Test case: untag 1 tc/cs2109s tc/cs2100 tc/cs2103 (where cs2103 exists but cs2109s and cs2100 doesn’t)
      Expected: Only cs2103 course tag is removed from the 1st person in the list. Status message shows:
      Tags removed: [COURSE: cs2103]
      Tags not found: [COURSE: cs2109s, COURSE: cs2100]
      
  3. Removing tags from a person where all tags don’t exist

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure the first person has no existing tags.

    2. Test case: untag 1 tg/nonexistent
      Expected: No changes made. Error details shown in the status message indicating that none of the specified tags were found.

    3. Test case: untag 1 tr/notfound tg/missing
      Expected: No changes made. Error details shown in the status message indicating that none of the specified tags were found.

  4. Invalid untag commands

    1. Test case: untag
      Expected: No tag removed. Error details shown in the status message indicating invalid command format and command usage.

    2. Test case: untag 0
      Expected: No tag removed. Error details shown in the status message indicating index must be a positive integer (1, 2, 3…).

    3. Test case: untag 1 test (missing prefix)
      Expected: No tag removed. Error details shown in the status message indicating invalid command format and command usage.

    4. Test case: untag 1 n/alice (invalid prefixes)
      Expected: No tag removed. Error details shown in the status message indicating invalid command format and unexpected extra input.

    5. Test case: untag 1 tr/ (missing value)
      Expected: No tag removed. Error details shown in the status message indicating invalid command format and empty value provided for prefix.

    6. Test case: untag 100 tg/friends (where 100 is larger than list size)
      Expected: No tag removed. Error details shown in the status message indicating no person exists at that index and tip to use list command.

    7. Test case: untag 1 tr/tutor space
      Expected: No tag removed. Error details shown in the status message indicating tags names should be alphanumeric (no spaces or special characters).

Clearing all tags of a specific type

  1. Clearing all tags from a person

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure both first and second person have existing general and role tags.

    2. Test case: cleartag 1 tg/
      Expected: All the general tags are cleared from the 1st person in the list. Status message shows the details of the general tags cleared.

    3. Test case: cleartag 2 tr/
      Expected: All the role tags are cleared from the 2nd person in the list. Status message shows the details of the role tags cleared.

  2. Clearing all tags from a person where no tags of specified type exist

    1. Prerequisites: List all persons using the list command. Multiple persons in the list. Ensure both first and second person has no existing tags.

    2. Test case: cleartag 1 tc/
      Expected: No changes made. Error details shown in the status message indicating that no course tags found to clear.

    3. Test case: cleartag 2 tr/
      Expected: No changes made. Error details shown in the status message indicating that no role tags found to clear.

  3. Invalid cleartag commands

    1. Test case: cleartag
      Expected: No tag cleared. Error details shown in the status message indicating invalid command format and command usage.

    2. Test case: cleartag 0
      Expected: No tag cleared. Error details shown in the status message indicating index must be a positive integer (1, 2, 3…).

    3. Test case: cleartag 1 (missing prefix)
      Expected: No tag cleared. Error details shown in the status message indicating invalid command format and command usage.

    4. Test case: cleartag 1 n/alice (invalid prefixes)
      Expected: No tag cleared. Error details shown in the status message indicating invalid command format and unexpected extra input.

    5. Test case: cleartag 1 tr/ tr/ (multiple same prefixes)
      Expected: No tag cleared. Error details shown in the status message indicating multiple values specified for the following single-valued field(s): i/.

    6. Test case: cleartag 1 tr/ tg/ (multiple prefixes)
      Expected: No tag cleared. Error details shown in the status message indicating invalid command format and command usage.

    7. Test case: cleartag 100 tg/ (where 100 is larger than list size)
      Expected: No tag cleared. Error details shown in the status message indicating no person exists at that index and tip to use list command.

    8. Test case: cleartag 1 tr/tutor
      Expected: No tag cleared. Error details shown in the status message indicating invalid command format and prefix should not contain any value.

Sorting persons

  1. Sorting by a valid field

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: sort o/name
      Expected: Contact list is sorted alphabetically by name (ascending). Status message shows Sorted by name (ascending).

    3. Test case: sort o/name r/
      Expected: Contact list is sorted alphabetically by name (descending). Status message shows Sorted by name (descending).

    4. Test case: sort o/email
      Expected: Contact list is sorted by email address (ascending). Status message shows Sorted by email (ascending).

    5. Test case: sort o/phone
      Expected: Contact list is sorted by phone number (ascending). Contacts with no phone number appear at the end of the list. Status message shows Sorted by phone (ascending).

    6. Test case: sort o/email r/
      Expected: Contact list is sorted by email address (descending). Status message shows Sorted by email (descending).

  2. Resetting sort order

    1. Test case: sort o/none
      Expected: Contact list reverts to the default (insertion) order. Status message shows Sort order reset to default.

    2. Test case: sort o/none r/
      Expected: Sort order is not reset. Error details shown in the status message indicating that r/ cannot be used with o/none.

  3. Invalid sort commands

    1. Test case: sort
      Expected: List is not sorted. Error details shown in the status message.

    2. Test case: sort o/INVALID
      Expected: List is not sorted. Error details shown in the status message indicating the unsupported order value.

    3. Test case: sort o/NAME (uppercase)
      Expected: List is sorted by name. Order values are case-insensitive.

    4. Test case: sort o/name r/value
      Expected: List is not sorted. Error details shown in the status message indicating that r/ does not accept a value.

    5. Test case: sort o/name o/email
      Expected: List is not sorted. Error details shown in the status message indicating duplicate o/ prefix.

Locating persons by name/email/tag

  1. Searching by single field

    1. Prerequisites: List all persons using the list command. At least one person should be in the list.

    2. Test case: find n/Alex
      Expected: Contacts whose names match Alex (case-insensitive; supports substring and fuzzy matching) are shown.

    3. Test case: find e/nus.edu
      Expected: Contacts with email addresses containing nus.edu (case-insensitive substring) are shown.

    4. Test case: find t/friends
      Expected: Contacts with the tag friends (case-insensitive exact match) are shown.

  2. Searching by multiple keywords/fields

    1. Prerequisites: List all persons using the list command. At least two persons should be in the list.

    2. Test case: find n/Alex David
      Expected: Contacts whose names match Alex OR David are shown (i.e. matches at least one keyword).

    3. Test case: find n/Alex e/nus.edu
      Expected: Contacts whose names match Alex AND whose email contains nus.edu are shown.

    4. Test case: find n/Alex e/nus.edu t/friends
      Expected: Contacts matching all three criteria (Name AND Email AND Tag) are shown.

  3. Fuzzy search for names (slight typo tolerance)

    1. Prerequisites: A contact with name Alice Tan exists.

    2. Test case: find n/alce
      Expected: Alice Tan is shown in the results.

    3. Test case: find n/aliec
      Expected: Alice Tan is shown in the results.

    4. Test case: find n/Tan
      Expected: Alice Tan is shown in the results.

  4. Invalid search commands

    1. Test case: find (no parameters)
      Expected: Error message indicating invalid command format and showing usage.

    2. Test case: find n/
      Expected: Error message indicating empty value provided for prefix n/.

    3. Test case: find n/!@#
      Expected: Error message indicating that the keyword !@# contains only special characters and must contain at least one alphanumeric character.

    4. Test case: find p/91234567 (unsupported prefix for find)
      Expected: Error message indicating unexpected extra input p/91234567.

Undoing the last action

  1. Undoing the most recent undoable command

    1. Prerequisites: List all persons using the list command. At least one person exists in the list.

    2. Test case: add n/John Doe e/johndoe@example.com followed by undo
      Expected: The previously added contact is removed from the list. Status message indicates that the last add action has been undone.

    3. Test case: delete i/1 followed by undo
      Expected: The deleted contact is restored to the list. Status message indicates that the last delete action has been undone.

  2. Undoing multiple commands consecutively

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: Execute add n/A e/a@example.com, then add n/B e/b@example.com, then undo, then undo
      Expected: Both added contacts are removed one by one in reverse order. Status message reflects each undo operation.

  3. Undo when no undoable commands are available

    1. Prerequisites: Start the application fresh, or ensure all previous undoable commands have already been undone.

    2. Test case: undo
      Expected: No changes to the contact list. Error details shown in the status message indicating that there are no actions to undo.

  4. Undo after non-undoable commands

    1. Prerequisites: List all persons using the list command.

    2. Test case: add n/John Doe e/johndoe@example.com, then list, then undo
      Expected: The previously added contact is removed. The list command does not affect undo history.

    3. Test case: help, then undo
      Expected: No changes to the contact list. Error details shown in the status message if there are no undoable commands.

  5. Undo after a mix of commands

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: add n/A e/a@example.com, list, delete i/1, then undo
      Expected: The deleted contact is restored. The list command is ignored by undo.

  6. Invalid undo command

    1. Test case: undo extra
      Expected: No changes to the contact list. Error details shown in the status message indicating that the command does not accept parameters.
  7. Persistence after undo

    1. Prerequisites: List all persons using the list command.

    2. Test case: add n/John Doe e/johndoe@example.com, then undo, then restart the application
      Expected: The contact list reflects the undone state (i.e., the added contact does not appear).

  1. Cycling through past commands

    1. Prerequisites: Enter at least three commands in sequence, e.g. list, sort o/name, help.

    2. Press the Up arrow key in the command box.
      Expected: The command box fills with the most recently entered command (help).

    3. Press Up again.
      Expected: The command box shows the previous command (sort o/name).

    4. Press Down.
      Expected: The command box shows the next command in history (help).

  2. Navigating beyond history bounds

    1. Press Up repeatedly past the oldest command in history.
      Expected: The command box stays at the oldest command; it does not wrap around.

    2. Press Down past the most recent command.
      Expected: The command box clears (returns to empty input).

  3. History is not affected by invalid commands

    1. Enter a valid command (e.g. list), then an invalid command (e.g. badcommand).

    2. Press Up once.
      Expected: The invalid command badcommand is shown (all submitted input, valid or not, is recorded).

Using keyboard shortcuts

  1. Clearing the input box

    1. Prerequisites: Application is running. Some text is present in the input box.

    2. Test case (Windows/Linux): Press Delete
      Expected: The input box is cleared.

    3. Test case (macOS): Press fn + Delete
      Expected: The input box is cleared.

  2. Exiting the application

    1. Prerequisites: Application is running.

    2. Test case (Windows/Linux): Press F3
      Expected: The application closes.

    3. Test case (macOS): Press fn + F3
      Expected: The application closes.

  3. Opening help

    1. Prerequisites: Application is running.

    2. Test case (Windows/Linux): Press F1
      Expected: The User Guide opens in the system default browser.

    3. Test case (macOS): Press fn + F1
      Expected: Same as above.

  4. Listing all contacts

    1. Prerequisites: Application is running.

    2. Test case (Windows/Linux): Press F2
      Expected: All contacts are displayed in the list.

    3. Test case (macOS): Press fn + F2
      Expected: Same as above.

  5. Invalid or unsupported key combinations

    1. Test case: Press unrelated keys (e.g., F4, Ctrl + F1)
      Expected: No action is triggered. Application remains unchanged.

Saving data

  1. Dealing with a missing data file

    1. Prerequisites: Locate the data file at data/addressbook.json. Delete it.

    2. Relaunch the application. Expected: The application starts with the sample contact list. A new data file is created automatically.

  2. Dealing with a corrupted data file

    1. Prerequisites: Locate the data file at data/addressbook.json. Open it in a text editor and introduce invalid content (e.g., delete a closing brace } or replace a field value with gibberish).

    2. Relaunch the application. Expected: The application starts with an empty contact list. The corrupted file is not loaded to prevent data loss from bad state.

  3. Auto-saving after changes

    1. Prerequisites: Application is running.

    2. Test case: Add a new contact, then close the application using the close button. Relaunch. Expected: The newly added contact is present.