This project is a modified version of AddressBook-Level 3 (AB3), created by the SE-EDU initiative.
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.Security: Validates password presence and handles initial configuration.Logic: The command executor and handler for App Mode.Model: Holds the data of the App in memory.Storage: Reads data from, and writes data to, the hard disk.Commons represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.
Each of the four main components (also shown in the diagram above),
interface with the same name as the Component.{Component Name}Manager class (which follows the corresponding API interface mentioned in the previous point.For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, CommandHistory, PersonListPanel, StatusBarFooter etc. All these, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
The UI component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
The UI component,
Logic component.Model data so that the UI can be updated with the modified data.Logic component, because the UI relies on the Logic to execute commands.Model component, as it displays Person object residing in the Model.API : Security.java
The Security component is responsible for the application's integrity check upon startup.
password field in the storage file is present and contains valid characters (not just empty or whitespace).Main indicating whether the application should proceed to the Password Setup screen or the standard Locked Mode.Logic and Model components.The sequence diagram below illustrates the interactions during the startup phase, showing how the Security component determines the initial UI state.
How the startup check works:
MainApp calls Security#getStartupStatus().Security queries Storage for the current password configuration.Security returns a status code.MainApp then initializes either the MainWindow or the PasswordSetupWindow based on that status.API : Logic.java
Here's a (partial) class diagram of the Logic component:
The sequence diagram below illustrates the interactions within the Logic component, taking execute("delete 1") API call as an example.
Note: The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
The sequence diagram below illustrates the interactions within the Logic component for a state-changing command, taking execute("unlock myPassword123") API call as an example.
This diagram shows how the UnlockCommand validates a password against the stored credentials in the Model and transitions the application to the UNLOCKED state upon successful authentication.
How the Logic component works:
Logic is called upon to execute a command, it is passed to an AddressBookParser object which in turn creates a parser that matches the command (e.g., DeleteCommandParser) and uses it to parse the command.Command object (more precisely, an object of one of its subclasses e.g., DeleteCommand) which is executed by the LogicManager.Model when it is executed (e.g., to delete a person).
Logic is also responsible for managing state transitions; it passes the current AppMode (Locked or Unlocked) down to the Model for execution.CommandResult object which is returned back from Logic.Here are the other classes in Logic (omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AddressBookParser class creates an XYZCommandParser (XYZ is a placeholder for the specific command name e.g., AddCommandParser) which uses the other classes shown above to parse the user command and create a XYZCommand object (e.g., AddCommand) which the AddressBookParser returns back as a Command object.XYZCommandParser classes (e.g., AddCommandParser, DeleteCommandParser, ...) inherit from the Parser interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model component,
Person objects (which are contained in a UniquePersonList object).Person objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Person> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.UserPref object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref objects.Model represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a Tag list in the AddressBook, which Person references. This allows AddressBook to only require one Tag object per unique tag, instead of each Person needing their own Tag objects.

API : Storage.java
The Storage component,
AddressBookStorage and UserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed).Model component (because the Storage component's job is to save/retrieve objects that belong to the Model)Classes used by multiple components are in the seedu.address.commons package.
Target user profile:
Value proposition: Spyglass provides a secure interface for managing sensitive contacts hidden from observers. It allows users to categorise private contacts, enabling the concealment of private data through commands that hides sensitive entries. This ensures the application maintains the appearance of a standard address book, providing a layer of plausible deniability.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * | Contact Manager | add a contact with essential details | store new social connections efficiently. |
* * * | Contact Manager | view a list of public contacts | see my everyday connections at a glance. |
* * * | Discreet Contact Manager | delete sensitive contacts while in Unlocked mode | remove specific records permanently to avoid detection. |
* * * | Discreet Contact Manager | switch to Locked mode instantly | hide private data and display a harmless interface to onlookers. |
* * * | Privacy-Conscious User | set a secure password upon initial launch | ensure only I can access the locked mode of the app. |
* * * | Privacy-Conscious User | unlock the app using a secret password | transition from the public view to my private contact list. |
* * | Contact Manager | edit contact information | keep my records accurate and up to date. |
* * | Discreet Contact Manager | search through hidden contacts by keyword | quickly retrieve sensitive information without manual scrolling. |
{More to be added}
(For all use cases below, the System is SpyGlass and the Actor is the user, unless specified otherwise)
Use case: UC1 - Initial password setup
Preconditions: The application is launched for the first time, or the password field in the data file is empty/invalid.
MSS
User launches SpyGlass.
SpyGlass detects no existing password and displays the Password Setup screen.
User enters a new password.
SpyGlass saves the password to the data file.
SpyGlass transitions to the main interface in Locked mode.
Use case ends.
Extensions
3a. The user enters a password consisting only of spaces or leaves it empty.
4a. SpyGlass fails to write to the data file.
Use case: UC2 - Lock application
Preconditions: User is in Unlocked mode.
MSS
User decides to hide their private contacts.
User enters the command lock.
SpyGlass switches the UI from Unlocked mode to Locked mode.
SpyGlass continues operating as a normal-looking addressbook application.
Use case ends.
Extensions
Use case: UC3 - Unlock application
MSS
User is currently interacting with the Locked mode.
User enters the secret password previously set.
SpyGlass switches the UI from Locked mode to Unlocked mode.
SpyGlass loads the Unlocked mode contact list and shows a success message.
Use case ends.
Extensions
Use case: UC4 - Add a contact
MSS
User requests to add a contact with required details.
User adds the new contact with relevant details.
SpyGlass saves the new contact to the current mode's storage and updates the display.
SpyGlass updates the command history to show the user added a new contact.
Use case ends.
Extensions
3a. A required parameter is missing.
3b. A parameter fails validation.
4a. The contact already exists in the current mode.
Use case: UC5 - Delete a contact
MSS
User requests to delete a specific contact in the list by index.
SpyGlass deletes the contact from the current mode's storage.
SpyGlass updates the contact list display.
SpyGlass updates the command history to reflect the user deleted a contact.
Use case ends.
Extensions
1a. The given index is invalid.
2a. SpyGlass fails to save the deletion to storage.
Use case ends.
{More to be added}
17 or above installed.{More to be added}
lock only works when the app is Unlocked).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 and setup
java -jar addressbook.jar.myPassword123) and confirm it.Invalid Password Setup
data/addressbook.json file to reset the app.Unlocking the app
unlock myPassword123 (using the password set during setup).unlock wrongPassword.Unknown command message is shown to mask the authentication attempt.Locking the app
lock.delete 1.data/addressbook.json. Launch the app.
data/addressbook.json and remove a bracket or quote to make the JSON invalid.
password field to "".
Saving window state
{ more test cases … }