By: Team Naggy Joel      Since: Mar 2020      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit diagrams.

Main has two classes called Main and MainApp. It is responsible for,

  • At app launch: Initializes the components in the correct sequence, and connects them up with each other.

  • At shut down: Shuts down the components and invokes cleanup method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of 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.

Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

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.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses 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.

2.3. Logic component

LogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the AddressBookParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a person).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. Model component

ModelClassDiagram
Figure 7. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the Address Book data.

  • exposes 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.

  • does not depend on any of the other three components.

As a more OOP model, we can store a Tag list in Address Book, which Person can reference. This would allow Address Book to only require one Tag object per unique Tag, instead of each Person needing their own Tag object. An example of how such a model may look like is given below.

BetterModelClassDiagram

2.5. Storage component

StorageClassDiagram
Figure 8. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Address Book data in json format and read it back.

2.6. Common classes

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

3. Implementation

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

tag::schedule[]

(Elysia Tan Ziyi: 3.1, 3.2)

3.1. Schoolwork Tracker

The SchoolworkTracker helps users keep track of their assignments so that they do not accidentally overlook any of them. It consists of the AssignmentList which contains all the added assignments.

From Fig 1 below, each Assignment has four components: Title, Deadline, Status and Workload. Workload refers to the expected amount of time required to finish the Assignment. These components will be used for schedule generation when (st)schedule n/NUM_DAYS is executed (explained below).

stClassDiagram

Fig 1. Class Diagram detailing the main components of the SchoolworkTracker

3.2. Schedule

3.2.1. Current Implementation

Schedule is facilitated by the SchoolworkTracker. This feature enhances the basic form of the SchoolworkTracker by allowing users to better visualise their current commitments so that they can better manage their time to pursue social events. This feature aims to distribute Workload as evenly as possible while ensuring that the user is able to complete the Assignment before the Deadline, unless it is impossible (i.e. Workload exceeds the amount of time the user has before the Deadline after taking into account more urgent assignments). A sample result is shown in Fig 2 below.

scheduleResult

Fig 2. Sample result of the generated schedule

It utilizes the existing Assignment stored in the SchoolworkTracker and implements ScheduleList which represents the generated schedule.

As seen from Fig 3 below, ScheduleList consists of Day objects and each Day has 3 components. totalAllocatedHours represents the total number of hours allocated to the Day. dueAssignment refers to an assignment that is due on the Day and allocatedAssignment represents an assignment that has been scheduled to be done on that Day. The latter also has an additional field allocatedHours which correspond to the suggested amount of time that should be spent on the assignment on that Day.

scheduleClassDiagram

Fig 3. Class Diagram detailing the main components of ScheduleList

Given below is a detailed example of how the schedule command behaves at each stage.

Step 1: User launches Naggy Joel for the first time. SchoolworkTracker is initialized to an empty list.

Step 2: User executes the add assignment command [(st)add n/NAME d/DEADLINE e/ESTIMATED_COMPLETION_HOURS] to add assignments to the SchoolworkTracker.

Step 3: User wants to better understand his schedule for the next 5 days before deciding whether he has time to hang out with his friends and executes (st)schedule n/5.

As seen from Fig 4 below, after the user enters the schedule command, the command will first be checked for validity. If it is not valid, the user will be informed and can then choose whether to re-enter the command or enter another command. On the other hand, if the input command is valid, the application will proceed to generate his schedule and after display it on the GUI.

scheduleActivityDiagram

Fig 4. Activity Diagram summarizing what happens when the schedule command is entered

The specific workings of the schedule command will be explained in the paragraphs below.

As seen from Fig 5 below, arguments from the input command is first parsed using the ScheduleCommandParser which converts the string variable into an integer and then passes it to ScheduleCommand for use later on and represents the NUM_DAYS queried. If the input argument is invalid, a ParseException is thrown instead and the user will be notified of the proper command usage. If the command is valid, the ScheduleCommand object will be created and returned to the LogicManager who will then call the execute() method in ScheduleCommand.

scheduleCommandGeneration

Fig 5. Sequence Diagram depicting the creation of ScheduleCommand object

As seen from Fig 6 below, the necessary preparations will be made before the schedule is being generated:

  1. The ScheduleCommand will retrieve the filteredAssignments from the Model component.

  2. The ScheduleList will then be initialized to have a size equals to the NUM_DAYS queried by the user, which in this example is 5 since the user typed (st)schedule n/5.

scheduleCommandExecution

Fig 6. Sequence Diagram showing the execution of the ScheduleCommand

The schedule generation process will be explained next and begins with Fig 7 all the way to Fig 9.

In Fig 7 below, filteredAssignments is iterated through in sorted order, starting with the Assignment due the earliest and for all assignments:

  1. The Status and Deadline of the Assignment will be retrieved.

  2. If Status is uncompleted and Deadline is not over, Workload will be distributed.

generateSchedule

Fig 7. Sequence Diagram showing the process of generating the schedule

As shown in Fig 8 below, for each uncompleted Assignment:

  1. Workload is retrieved and distributed across several days, from query date to deadline, incrementally so as to generate a balanced schedule.

  2. The final allocation of hours, including amount unscheduled, is recorded and the Assignment will be recorded as a dueAssignment if its deadline falls within the range of days queried.

handleUncompletedAssignment

Fig 8 Sequence Diagram showing how an uncompleted Assignment is handled

allocateHours

Fig 9. Sequence Diagram showing how the workload of an assignment is distributed

From Fig 9 above, assignments due on query date are handled differently from those that are not.

  • Assignment due on query date: The amount of time that can be allocated to the assignment will be capped at the amount of time available before the Deadline.

  • Assignment not due on query date: Incremental distribution of Workload starting from days with no allocated hours, then days with least amount of allocated hours and lastly allocating evenly.

    • Between query date and deadline (both exclusive): Available time is capped at 24 hours.

    • Query date: Available time is capped at the amount of time left in the day.

    • Deadline: Available time is capped at the amount of time before the assignment is due.

Actual caps are as above but after accounting for hours already allocated to other assignments.

Once the user’s schedule is generated, ScheduleList is updated with the allocationResult, a CommandResult object will be created and returned to LogicManager. LogicManager returns it to MainWindow who will then retrieve the generated schedule and display it as shown in Fig 10 below.

getUi

Fig 10. Sequence Diagram showing how the generated schedule is retrieved

Step 4: Based on the results, the user can then decide on how to best schedule his outing.

3.2.2. Design Considerations

Aspect: Distribution of estimated work hours for each assignment
  • Current choice: Hours are allocated incrementally to achieve a balanced schedule while still ensuring that deadlines can be met (unless impossible due to the constraints of time left)

    • Pros: Better reflects the real-world scenario where students are more likely to spread out their work and encourages work life balance which is the main selling point of Naggy Joel.

    • Cons: Complicated algorithm is more prone to errors.

  • Alternative: For each day, cumulatively add Workload divide by Number of days to deadline for all assignments

    • Pros: Easier to implement.

    • Cons: Some days may have impossibly high workload, deadlines are not handled properly.

Aspect: Variable type to be used for calculations during distribution of workload
  • Current choice: Use of BigDecimal for calculations

    • Pros: More accurate allocation of hours while minimizing lost hours due to rounding errors.

    • Cons: Harder to handle and new objects have to be created each time.

  • Alternative: Restrict calculations to the use of integer

    • Pros: Easier to handle and more accurate comparisons can be made as compared to when floats are used as floating point arithmetic is not exact.

    • Cons: A lot of unnecessary ‘loss’ in allocated and available time due to rounding errors.

end::schedule[]

tag::get[]

(Kwan Xin Jie: 3.3, 3.4, 3.5)

3.3. Detailed Contact Viewer

3.3.1. Implementation

The detailed contact viewer is facilitated by AddressBook. This feature allows a user to view a particular contact details in entirety.

Given below is an example usage scenario and how the get mechanism behaves at each step.

Step 1. The user launches the application for the first time. The AddressBook will be initialized with the initial state, which is an empty list.

Step 2. The user executes the (ab)add n/David p/12345 …​ command to add a new person.

Step 3. The user executes the (ab)get 1 command to get the detailed contact of the first person in the AddressBook list.

detailedContact

The following sequence diagram shows how the get operation works within the Logic component:

getCommand

3.3.2. Design Considerations

Aspect: What information to display
  • Alternative 1 (current choice): Set a limit on details that has a potential long list (such as NoteTaker) and display them on the detailed contact viewer.

    • Pros: All information are displayed for easier viewing/access.

    • Cons: AddressBook list might be long and hard to view.

  • Alternative 2: Display selective information on the AddressBook list and the full information under get command.

    • Pros: AddressBook list is less cluttered.

    • Cons: Omits certain information.

end::get[]

tag::sortAssgn[]

3.4. Sorting of Assignments

3.4.1. Implementation

The sorting of assignments is facilitated by AssignmentList. This feature allows a user to sort assignments by deadline or estimated completion time.

Given below is an example usage scenario and how the sort mechanism behaves at each step.

Step 1. The user launches the application for the first time. The 'AssignmentList' will be initialized with the initial state, which is an empty list.

Step 2. The user executes the following commands to add new assignments.

  • 1. (st)add t/CS2103 Project d/2020-04-18 23:59 e/180

  • 2. (st)add t/DBA3702 Project d/2020-04-19 19:00 e/150

  • 3. (st)add t/CS2106 Lab d/2020-04-11 20:00 e/20

Step 3. The user executes the (st)list -d command to sort the assignments by deadline.

The following sequence diagram shows how the list assignment operation works within the Logic component:

listAssgnCommand

3.4.2. Design Considerations

Aspect: How to sort assignment by estimated completion time
  • Alternative 1 (Current choice): Descending order

    • Pros: User can prioritise by doing the assignment which takes the longer first.

    • Cons: User may spend too much time on assignments that take much longer.

  • Alternative 2: Ascending order

    • Pros: User can clear more assignments faster, by completing those that takes a shorter amount of time first.

    • Cons: User may delay starting on assignments that take longer and risk having uncompleted assignments at the deadline.

end::sortAssgn[]

tag::editRestNote[]

3.5. Editing of Restaurant Notes

3.5.1. Implementation

The editing of restaurant notes is facilitated by RestaurantBook. This feature allows a user to edit existing notes of a restaurant in the list.

Given below is an example usage scenario and how the editing of note mechanism behaves at each step.

Step 1: The user launches the application for the first time. The RestaurantBook will be initialized with the initial state, which is an empty list.

Step 2: The user executes the following commands to add notes to a restaurant.

  • 1. (rt)add n/Ameens l/Clementi v/No o/0900:2300 p/$ c/Indian

  • 2. (rt)addnote r/Cheese fries

Step 3: The user executes the (rt)editnote 1 rl/1 r/Butter chicken command to edit the first recommended food of the restaurant at index 1, to Butter chicken.

The following sequence diagram shows how the edit restaurant note operation works within the Logic component.

addRestNote

3.5.2. Design Considerations

Aspect: How to execute the command for edit note, given 3 editable notes for a restaurant.
  • Alternative 1 (chosen): Have one command that allows user to choose any note to edit.

    • Pros: Easy for user to use, without switching between different commands.

    • Cons: As line number of the relevant note needs to be indicated, many levels of checking of the user input is required, and is thus more prone to errors.

  • Alternative 2: Have 3 separate edit commands, one for each restaurant’s note.

    • Pros: Easier to implement.

    • Cons: Not user-friendly since different notes cannot be edited in a single command.

end::editRestNote[]

tag::findContacts[]

(Chua Xinhui Sarah: 3.6)

3.6. Finding Contacts

3.6.1. Implementation

The finding of a Person is facilitated by the Address Book. This feature allows for users to find a specific contact in their Address Book.

Given below is an example usage scenario and how the finding contact mechanism behaves at each step.

Step 1: The user launches the application for the first time. The Address Book will be initialized with the initial state, which is an empty list.

Step 2: The user executes the (ab)add n/Joel …​ command multiple times with different details of different people to add multiple people as contacts into the Address Book.

Step 3: The user executes the (ab)find …​ command to find their desired contacts in the AddressBook list. For instance, the user may do: * (ab)find o/NUS searches by organization. * (ab)find n/Joel Lim searches by name. * (ab)find t/friends searches by tags.

The following sequence diagram shows how the find operation works within the Logic component.

findPersonMain
findPersonRef

3.6.2. Design Considerations

Aspect: How to execute the command for finding a contact using Java Predicates, given that a Person has multiple tags.

Current implementation of Predicates uses the stream and anyMatch commands to check each keyword against one single word, but since a person may have multiple tags, the implementation needs to be able to check each keyword against multiple tags instead of a single tag.

  • Alternative 1 (chosen): Concatenate all the tags of a person together into a String, and check the provided tag keywords against that one String.

    • Pros: Easier to implement.

    • Cons: -

  • Alternative 2: For each person’s unique tags, create one Tag Predicate per tag.

  • Pros: Conceptually easier to understand, as well as to draw the UML diagram.

  • Cons: Many Tag Predicate objects would have to be created. This could be messy and cause debugging to be difficult.

Aspect: How to sort the provided keywords into different Predicates given that there are multiple fields we can search against (eg. Organization, Name, etc)
  • Alternative 1 (chosen): Have a loop to parse the keywords and sort them into different Predicate keyword lists depending on where the prefixes are located. For instance, if the user types (ab)find t/friends colleagues o/NUS, then the keywords friends and colleagues would to go to the Tag Predicate while the keyword NUS would be allocated to the Organization Predicate.

  • Pros: Easier for the user because they just have to demarcate which keywords are used for which using a single prefix.

  • Cons: More difficult to implement.

  • Alternative 2: Have the user include the prefix before every different keyword they want to search. For instance, if they want to search using 2 different tag keywords like "friends" and "colleagues", they would have to type (ab)find t/friends t/colleagues. Then we can use the Argument Multimap to tokenize the arguments.

  • Pros: Easier to implement.

  • Cons: More troublesome for the user because if they want to search for multiple tags, they would have to keep typing the /t prefix for each keyword. end::findContacts[]

tag::rtundoredo[]

(Joel Lim Hee Heng: 3.7, 3.8)

3.7. Restaurant Book

3.7.1. Current Implementation

The RestaurantBook helps users keep track of Restaurants, so that users can quickly find an eating place given their constraints (e.g. odd hours, location, food cravings, etc). We will briefly introduce the implementation and logic behind this component as a stepping stone to understand the undo/redo implementation in the next section.

The following depicts the class diagram for the Restaurant component of the application.

rtClassDiagram

Each Restaurant has 9 components Name, Location, Visit, Hours, Price, Cuisine, and 3 lists of Note to represent the recommended, good, and bad food that the user can input. visit represents whether the user has visited the restaurant, and hours represent the restaurant’s opening hours. The other fields are self-explanatory.

We will illustrate how commands to the RestaurantBook works using the simple (rt)add command, which adds a new Restaurant to the RestaurantBook.

rtAddActivityDiagram

The above shows a medium level abstraction of the activity diagram with swim lanes when the user enters a valid add restaurant command. Even though the command is valid, the parameters might not be, or the restaurant entered might be a duplicate (duplicate iff the name and phone matches). Hence, the corresponding units check for these executing the command.

Once these checks pass, before the ModelManager adds the new restaurant in, the ModelManager first does some housekeeping to support the undo/redo operation as seem in the activity diagram. This is the key we want to illustrate here to better understand undo/redo. This is very useful because all commands that change the state will go through a similar process. More details are given below.

3.8. Undo/Redo

3.8.1. Current Implementation

This is the Class Diagram for the ModelManager and the ModelState, the 2 integral classes to understand the undo/redo operations. Note that we have omitted methods used to support other commands but are irrelevant to the undo/redo operation and also omitted the getter methods of the ModelState for better readability.

The undo/redo mechanism is facilitated by modifying ModelManager to include 3 additional attributes. undoStack: which stores the lists of ModelState from which the undo operation will draw upon redoStack: which stores the lists of ModelState from which the redo operation will draw upon ** currentModel: which is simply the ModelState that the application is currently in

ModelManagerClassDiagram

We will now go through a very simple example of how the undo/redo operation is implemented. Assume the following is the initial state:

  • Step 1: When the user launches the application for the first time, the undo stack is initialised to only 1 state, which is the current state. The redo stack will always be empty initially.

undo(1)
  • Step 2: Suppose the user executes (rt)add n/KFC l/East v/No to add a new restaurant. This is a command that changes the state of the model. Hence, the application will execute a series of commands that is equivalent to duplicating m0, pushing the duplicate into the undo stack, and then making the currentModel pointer point to the top of the stack. All changes will then be made to this new duplicate, with the previous state m0 intact at the bottom of the undo stack. The redo stack still remains empty.

undo(2)
  • Step 3: Now, suppose the user executes the undo command. The ModelManager will simply push the current state m1 into the redo stack, and make the current state pointer point to the resultant top element in the undo stack m0, which will be the state before the user entered the last command, effectively restoring the previous state. The redo stack simply stores all the undone states.

undo(3)

Note that if the user executes the undo command when the undo stack has only 1 state, an error will be returned.

  • Step 3.1: Now, if the user then executes the redo command, the application will simply push the top state m1 in the redo stack into the undo stack, and make the current state pointer point to the resultant top state in the undo stack again.

undo(3.1)

Note that if the user executes the redo command when the redo stack is empty, an error will be returned.

  • Step 3.2: However, suppose if instead of executing the redo command, the user executes another command that changes the state such as (rt)delete 1, apart from modifying the undo stack as we mentioned earlier when the user executes a command, the redo stack will also be emptied, since there is nothing to redo anymore.

undo(3.2)

This is a brief summary of how the undo/redo operation is implemented. In reality, the type of command that caused the change is also stored in the ModelState. This is to ensure that we can display the appropriate visual confirmation in the UI when the user executes an undo or redo command. For example, when the user redoes a command that added a restaurant, we will want to display the lists of restaurants instead of whatever the user is looking at now.

For greater detail, below is the sequence flow diagram when the user executes an undo command:

undoSequence(1)
undoSequence(2)

redo is simply the opposite of undo . Instead of popping from undo stack and pushing into redo stack, ModelManager pops from the redo stack and pushes the popped state into the undo stack. The current state is still the top of the undo stack.

The update() simply makes the other attributes of the ModelManager point to the corresponding ones in the current state. That is, to update them to point to the current copy. This makes the code cleaner as we don’t have to always access them from the currentModel pointer.

Lastly, do note that there are 2 types of commands: Commands that alters the state (e.g. add, edit): the ModelManager will do the housekeeping to duplicate the state before executing these commands Commands that do not alter the state (e.g. list, get): these commands do not alter the state, and the ModelManager will simply execute these commands without duplicating the state

3.8.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1: Creates and saves the entire state of the application from scratch

    • Pros: Easy to implement

    • Cons: Requires huge amount of memory

  • Alternative 2: Stores only the individual command entered

    • Pros: Minimal memory usage

    • Cons: More difficult to ensure correctness as there will be many more alternate paths (scales as the number of commands go up)

  • Alternative 3 (current choice): Partially stores the entire application

    • Pros: Easy to implement

    • Cons: Require significant amount of memory, but less than alternative 1

For alternative 3, the current implementation seems to store the entire application, but in reality, the end objects that the pointers in each ModelState are pointing to are largely the same. For example, suppose we have 1,000 persons in the AddressBook and we edit person 1000. The new ModelState actually points to the same Person object for the 1st 999 objects and only differs in the 1000th object.

Aspect: Which commands will cause a state change
  • Alternative 1: Every command will generate a new state

    • Pros: Easy to implement (need not differentiate); can be more intuitive to some users (e.g. the user accidentally (rt)list and would like to go back to what the user was viewing previously)

    • Cons: Requires more memory; can be less intuitive to some users as the undo for commands such as (rt)list only changes what the user sees but does not perform any real changes to the state

  • Alternative 2 (current choice): Only commands that change the state will cause state transitions

    • Pros: Less memory usage, can be more intuitive to some users; in reality, difficult to tell which is more intuitive to users without more data

    • Cons: More difficult to ensure correctness as we need to ensure the exact set of commands that cause state transitions

Aspect: What to show when the user executes a undo or redo
  • Alternative 1: Simply show the same screen

    • Pros: Easy to implement, need to only take care of the backend without worrying about the UI; user might not want to move away from his/her current screen

    • Cons: User has no confirmation that the undo did happen (e.g. if the user undoes adding a restaurant but we don’t show the updated restaurant list)

  • Alternative 2 (current choice): Displays what the user has undone/redone (e.g. if the user undoes adding a note to a contact, we should show the details of that contact upon the undo operation)

    • Pros: Gives user confirmation of the new data and that the command is indeed undone

    • Cons: More difficult to implement and requires more memory as we will have to store more information to flash to the user the correct screen that corresponds to the command

end::rtundoredo[]

3.9. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 3.10, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

3.10. Configuration

Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile: Busy university students who want to balance their hectic work schedule as well as their social life.

  • Has the need to manage a significant number of contacts and project/assignment deadlines

  • Has the need to manage a significant number of friends' birthdays and their miscellaneous information (such as their likes and dislikes)

  • Can type fast and prefers typing over mouse input

  • Is reasonably comfortable using CLI applications

  • Prefers desktop applications instead of other applications

Value proposition: A one-stop application for managing your social life, allowing you to manage contacts faster than a typical mouse/GUI driven app.

  • Afraid that you will forget your best friend’s birthday? Naggy Joel will remind you!

  • Not sure where you want to hang out? Naggy Joel can suggest places for you!

  • Want to hang out with your friends but not sure when you can because of your hectic university schedule and many deadlines? Naggy Joel will help you find the time!

Appendix B: User Stories

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

Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the app

* * *

user

add new contact

so that I can expand my address book

* * *

user

list all my contacts according to particular filters

easily search and locate the people I want to find according to certain filters

* * *

user

edit my contacts

update my contacts’ information to ensure accuracy of my data

* * *

busy university student

be reminded of my friends' birthdays as and when they are approaching

have no need to memorize all my friends' birthdays

* * *

busy university student with many groupmates and friends

find and sort contacts by certain criteria (eg. find by name, find by tags, find by organization)

locate my friends and groupmates easily

* * *

user

undo and redo commands

reverse mistakes.

* * *

user

view a contact in its entirety

see all the information pertinent to a particular contact

* * *

user

add notes to a particular contact

store additional useful information pertaining to a particular contact

* * *

busy university student with many assignments and project deadlines scattered throughout the semester

be provided timely reminders of my work deadlines

not have to remember the specific timing, date and deliverables of each assignment.

* * *

busy university student with a hectic work schedule

get a sense of how free I am to go out with my friends and pursue other social events given my upcoming deadlines

pursue social events without missing my deadlines

* *

busy university student with a hectic work schedule

be able to be suggested places to eat with my friends based on "KIV" notes for certain restaurants

choose a gathering place without much hassle

* * *

university student who wants to live life to the fullest

be able to schedule social events whenever I have free time

still hang out with my friends amidst all the school work.

* * *

university student with many places to explore

be able to keep track of the different must-try food places

visit them when hanging out with friends.

* * *

university student with many places to explore

be able to keep track of the different food places that opens at odd times

eat when I’m studying until the wee hours.

* * *

university student with different groups of friends

be able to categorise my contacts

know how I met them.

* * *

user

be able to delete unwanted contacts/details

keep the application free from clutter and ensure that it does not take up unnecessary space.

* * *

user

be able to keep track of the restaurants I have visited

have a list of restaurants to go to when I have no preferences.

* * *

university student who aims to have a good social life

be able to remember miscellaneous information about my friends

easily find places to hang out with my friends and identify gifts to buy for their birthdays.

* * *

university student with many assignment to keep track of

mark assignments as done

have a better idea of my remaining assignments.

* * *

busy university student with many assignments and projects

add an assignment to the app

not have to remember the details and deliverables of each assignment.

* * *

busy university student with many events to attend and friends to catch up with

keep track of all the events that I need to attend

do not miss any meetings and anger anyone.

* *

user who has visited many different restaurants

be able to keep track of terrible dishes at each restaurant

I can avoid ordering them again.

Appendix C: Use Cases

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

Use case: Adding an assignment

MSS

  1. User adds an assignment by typing the "(st)add" command and includes description of the assignment, deadline, and number of estimated hours to complete the work.

  2. Naggy Joel adds the assignment to the list of assignments.

    Use case ends.

Extensions

  • 1a. The given description, deadline, and number of estimated hours to complete work is invalid/empty.

    • 1a1. Naggy Joel shows an error message.

    • 1a2. User enters new data
      Steps 1a1 and 1a2 are repeated until the data entered are correct
      Use case resumes at step 2.

Use case: Finding restaurants to hang out

MSS

  1. User requests to list out all upcoming social events.

  2. Naggy Joel lists out all upcoming social events, displaying the dates and times of each event.

  3. User chooses the event for which he wants to find a restaurant for and notes down the time and location.

  4. User searches for restaurants based on the location of the event.

  5. Naggy Joel lists out all restaurants that match the given location.

  6. User selects a restaurant based on the opening hours and the attendees of the event.

    Use case ends.

Extensions

  • 4a. There are no restaurants that match the location that the user used to search.

    • 4a1. Naggy Joel shows an error message.

    • 4a2. User searches using a nearby location
      Steps 4a1 and 4a2 are repeated until a restaurant is shown
      Use case resumes at step 2.

      Use case ends.

Use case: Finding time for a social event

MSS

  1. User requests to know his schedule for the upcoming period (can be the next day, week or month)

  2. Naggy Joel generates and displays the user’s schedule for the upcoming period.

  3. User chooses a period of free time as shown by Naggy Joel.

  4. User creates social event and inputs just the description of social event.

  5. Naggy Joel creates the social event and adds it to the list of upcoming social events.

    Use case ends.

Extensions

  • 4a. User cancels creating a social event.

    • 4a1. Naggy Joel cancels the creation of the social event.

      Use case ends.

Use case: Marking assignment as done

MSS

  1. User requests to list out all assignments with upcoming deadlines.

  2. Naggy Joel displays a list of all assignments with upcoming deadlines.

  3. User chooses the assignment which has been completed.

  4. Naggy Joel marks the indicated assignment as completed.

    Use case ends.

Use case: Keeping track of birthdays

MSS

  1. User requests to list out all upcoming birthdays.

  2. Naggy Joel displays a list of birthdays within the next 5 days (including current day), with the name, date and remarks.

  3. User views the remarks of the contact to decide on a suitable gift.

    Use case ends.

Appendix D: Non Functional Requirements

  1. The final product is a result of evolving/enhancing/morphing the given code base.

  2. The final product targets users who can type fast and prefer typing over other means of input.

  3. The final product should be for a single user.

  4. The product is developed incrementally over the project duration.

  5. The data should be stored locally and should be in a human editable text file.

  6. The data cannot be stored in a DBMS

  7. The software should follow the Object-Oriented paradigm primarily.

  8. The software should work on any mainstream OS such as Windows, Linux, and OS-X platforms and should avoid having OS-dependent libraries and OS-specific features.

  9. The software should work on a computer that has version 11 of Java installed.

  10. The software should work without requiring an installer.

  11. The software should not depend on a remote server.

  12. The use of third-party frameworks is subject to approval by the module administrators

  13. The file size of deliverables should not exceed 100MB for the JAR file and 15MB/file for the PDF files

  14. 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.

  15. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.

Appendix E: Glossary

Mainstream OS

Windows, Linux, OS-X

Appendix F: Instructions for Manual Testing

Given below are instructions to test the app manually.

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

F.1. 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 double-clicking the jar file.
      Expected: The most recent window size and location is retained.

tag::manual[]

F.2. Adding a person

  1. Test case: (ab)add n/John p/12345 o/NUS n/05-20
    Expected: A new contact with the name John, phone number 12345, and birthday 20 May is added to the list. Details of the added contact shown in the status message.

F.3. Deleting a person

  1. Deleting a person while all persons are listed

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

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

    3. Test case: (ab)delete 0
      Expected: No person is deleted. Error details shown in the status message.

    4. Other incorrect delete commands to try: (ab)delete, (ab)delete x (where x is larger than the list size)
      Expected: Similar to previous.

  2. Deleting a person while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)delete x (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No person is deleted. Error details shown in the status message.

F.4. Editing a person

  1. Editing a person while all persons listed

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

    2. Test case: (ab)edit 2 t/BFF -t/Friends
      Expected: Second contact in the list is edited, with tag "Friends" deleted, and tag "BFF" added. Details of the edited contact shown in the status message.

  2. Editing a person while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)edit x b/06-22 (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No person is edited. Error details shown in the status message.

F.5. Adding additional information to a person

  1. Adds note(s) to a person while all persons listed

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

    2. Test case: (ab)addnote 2 i/Likes red i/Lives in Jurong i/Cycles
      Expected: Second contact in the list has 3 new notes, "Likes red", "Lives in Jurong" and "Cycles", added. Details of the edited contact shown in the status message.

  2. Add note(s) to a person while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)addnote x i/Can’t take spicy (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No new note is added to a person. Error details shown in the status message.

F.6. Editing additional information for a person

  1. Editing an existing note of person while all persons listed

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

    2. Test case: (ab)editnote 2 l/2 i/Likes matcha
      Expected: Edits the second note of the second contact in the list to "Likes matcha". Details of the edited contact shown in the status message.

    3. Test case: (ab)editnote x i/Likes red (where x is larger than the number of existing notes of a person)
      Expected: No note is edited for the person. Error details shown in the status message.

    4. Other incorrect commands to try: (ab)editnote 2 l/aaa i/Likes cats (where line number is not an integer)
      Expected: Similar to previous

  2. Editing an existing note of a person while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)editnote x l/3 i/Can’t take spicy (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No note is edited for a person. Error details shown in the status message.

F.7. Deleting additional information of a person

  1. Delete note(s) of a person while all persons listed

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

    2. Test case: (ab)deletenote 2 l/1 l/3
      Expected: Deletes the first and third note of the second contact in the list. Details of the edited contact shown in the status message.

    3. Test case: (ab)deletenote 2 l/x (where x is larger than the number of existing notes of a person)
      Expected: No note is deleted for the person. Error details shown in the status message.

    4. Other incorrect commands to try: (ab)deletenote 2 l/2 l/aaa (where line number is not an integer)
      Expected: Similar to previous

  2. Editing a person while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)deletenote x l/2 (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No note is deleted for a person. Error details shown in the status message.

F.8. Finding a specific contact/specific set of contacts

  1. Finding person(s) by organization, name or tag.

    1. Test case: (ab)find o/NUS n/Lim
      Expected: If person(s) with the organization "NUS" and have the word "Lim" in the name, person(s) will be listed. The number of person listed shown in the status message.

F.9. Retrieving a specific contact and view in full details

  1. Retrieves a person contact while all persons listed

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

    2. Test case: (ab)get 2
      Expected: Display the second person in the full contact list. The number of person listed shown in the status message.

    3. Test case: (ab)get x (where x is larger than the number of contacts in the list)
      Expected: No detailed view of contact is displayed. Error details shown in the status message.

  2. Retrieves a person contact while finding contacts that meet certain criteria

    1. Prerequisites: List subset of contacts using the (ab)find command. Persons who meet the criteria are listed.

    2. Test case: (ab)get x (where x is larger than the filtered list size but smaller than the size of the full contact list)
      Expected: No detailed view of contact is displayed. Error details shown in the status message.

F.10. List contacts with upcoming birthdays

  1. All persons are listed

    1. (ab)birthday
      Expected: All contacts with birthdays in the next 5 days (current day included) should be listed.

F.11. Adding a restaurant

  1. Test case: (rt)add n/Ameens l/Clementi v/No o/0900:2300 p/$ c/Indian
    Expected: Adds a new restaurant called Ameens at Clementi with 1 dollar sign price point, opens from 9am to 11pm, with cuisine Indian and has yet to be visited.

F.12. List all restaurants saved

  1. (rt)list
    Expected: All restaurants added should be displayed.

F.13. Editing a restaurant

  1. Editing a restaurant while all restaurants are listed

    1. Prerequisites: List all restaurants using the (rt)list command. Multiple restaurants in the list.

    2. Test case: (rt)edit 1 v/Yes o/0900:2200
      Expected: Edits the first restaurant visited status to "Yes" and operating hours to "0900:2200".

  2. Editing a restaurant while finding restaurants that meet certain criteria

    1. Prerequisites: List subset of restaurants using the (rt)find command. Restaurants that meet the criteria are listed.

    2. Test case: (rt)edit x (where x is larger than the filtered list size but smaller than the size of the full restaurant list)
      Expected: No restaurant edited. Error details shown in the status message.

F.14. Deleting a restaurant

  1. Deletes a restaurant while all restaurants are listed

    1. Prerequisites: List all restaurants using the (rt)list command. Multiple restaurants in the list.

    2. Test case: (rt)delete 2
      Expected: Deletes the second restaurant in the restaurant list. Details of the deleted restaurant shown in the status message.

    3. Test case: (rt)delete x (where x is larger than the size of the restaurant list)
      Expected: No restaurant is deleted. Error details shown in the status message.

  2. Deleting a restaurant while finding restaurants that meet certain criteria

    1. Prerequisites: List subset of restaurants using the (rt)find command. Restaurants that meet the criteria are listed.

    2. Test case: (rt)delete x (where x is larger than the filtered list size but smaller than the size of the full restaurant list)
      Expected: No restaurant deleted. Error details shown in the status message.

F.15. Adding food note(s) to a restaurant

  1. Add food note(s) to a restaurant while all restaurants are listed

    1. Prerequisites: List all restaurants using the (rt)list command. Multiple restaurants in the list.

    2. Test case: (rt)addnote 1 r/Chicken Chop g/Truffle Fries b/Risotto b/Lobster Pasta
      Expected: Add notes to the restaurant at index 1 with recommended food Chicken Chop, good food Truffle Fries, and bad food Risotto and Lobster Pasta. Details of the edited restaurant shown in the status message.

F.16. Editing food note(s) of a restaurant

  1. Edit food note(s) to a restaurant while all restaurants are listed

    1. Prerequisites: List all restaurants using the (rt)list command. Multiple restaurants in the list.

    2. Test case: (rt)editnote 1 rl/1 r/Fish and Chip gl/1 g/Mushroom soup bl/2 b/Salad
      Expected: Edit notes to the restaurant at index 3 with recommend food Fish and Chip at line number 1, good food Mushroom soup at line number 1, and bad food Salad at line number 2. Details of the edited restaurant shown in the status message.

    3. Test case: (rt)editnote 2 rl/aaa r/Fried Rice gl/1 g/Tomato soup (Non-integer line number for recommended food notes)
      Expected: No restaurant’s food notes is edited. Error details shown in the status message.

F.17. Deleting food note(s) of a restaurant

  1. Delete food note(s) to a restaurant while all restaurants are listed

    1. Prerequisites: List all restaurants using the (rt)list command. Multiple restaurants in the list.

    2. Test case: (rt)deletenote 1 rl/1 gl/1 bl/2
      Expected: Delete notes to the restaurant at index 1, at line number 1 of recommended food notes, at line number 1 of good food notes, at line number 2 of bad food notes.

    3. Test case (rt)deletenote 1 rl/1 gl/x bl/aaa (where x is larger than the size of good food notes, and non-integer line number for bad food notes)
      Expected: No restaurant’s bad notes is edited. Error details shown in the status message.

F.18. Search for restaurants based on a number of criteria

  1. (rt)find l/Clementi
    Expected: Searches and display restaurants in the Clementi area. Number of restaurants displayed shown in the status message.

F.19. Adding an assignment

  1. Test case: (st)add t/CS2103 post lecture quiz d/2020-11-11 23:59 e/2
    Expected: Adds an assignment titled CS2103 post lecture quiz to the Schoolwork Tracker, due 11 Nov 2020 23:59 PM and which takes an estimated two hours to complete. Details of the added assignment shown in the status message.

  2. Test case: (st)add t/CS2105 lab d/DEADLINE e/5 (where DEADLINE is before the current date and time)
    Expected: No assignment is added. Error details shown in the status message.

F.20. List current assignments

  1. Test case: (st)list -d
    Expected: Assignments will be shown in chronological order, with respect to the deadline, with all completed assignments at the bottom of the list.

  2. Test case: (st)list -e
    Expected: Assignments will be shown according to the estimated completed time in descending order with all completed assignments at the bottom of the list.

  3. Test case: (st)list -d -e
    Expected: Assignments will not be sorted. Error details shown in the status message.

F.21. Deleting an assignment

  1. Deletes an assignment while all assignments are listed

    1. Prerequisites: List all assignments using the (st)list command. Multiple assignments in the list.

    2. Test case: (st)delete 1
      Expected: Deletes the first assignment in the Schoolwork Tracker. Details of the deleted assignment shown in the status message.

    3. Test case: (st)delete x (where x is larger than the size of Schoolwork Tracker)
      Expected: No assignment is deleted. Error details shown in the status message.

F.22. Editing an assignment

  1. Edits an assignment while all assignments are listed

    1. Prerequisites: List all assignments using the (st)list command. Multiple assignments in the list.

    2. Test case: (st)edit 1 t/CS2103 Quiz e/1
      Expected: Changes the title of the first assignment to 'CS2103 Quiz' and estimated completion time to 1 hour. Details of the edited assignment shown in the status message.

    3. Test case: (st)edit 1 s/Completed
      Expected: Marks the first assignment in the Schoolwork Tracker as completed. Details of the edited assignment shown in the status message.

    4. Test case: (st)edit 1 s/Uncompleted
      Expected: Marks the first assignment in the Schoolwork Tracker as uncompleted. Details of the edited assignment shown in the status message.

    5. Test case: (st)edit d/DEADLINE (where DEADLINE is before the current date and time)
      Expected: No assignment is edited. Error details shown in the status message.

    6. Other incorrect commands to try: (st)edit x (where x is larger than the size of Schoolwork Tracker)
      Expected: Same as above

F.23. Generating schedule

  1. Generates the user’s schedule

    1. Prerequisites: There are assignments added to the SchoolworkTracker

    2. Test case: (st)schedule n/5
      Expected: The user’s schedule for the next 5 days is displayed. For the query date, the total allocated hours should not exceed the amount of time remaining on query date. For each assignment, the amount of time allocated to the day it is due should not exceed the amount of time the user has on that day before the time of submission. For each assignment, the total amount of time scheduled and unscheduled should equals the estimated workload of that assignment.

    3. Test case: (st)schedule n/-1
      Expected: No schedule is displayed. Error details shown in the status message.

F.24. Adding a social event

  1. Test case: (ev)add t/Facebook job interview d/2020-05-18 10:00 h/3 p/Facebook APAC HQ
    Expected: Adds a new social event with title "Facebook job interview", event date 2020-05-18, duration of 3 hours and location at "Facebook APAC HQ".

  2. Test case: (ev)add t/Birthday party d/DATETIME h/3 p/Clementi (where DATETIME is after the current date and time)
    Expected: No social event is added. Error details shown in the status message.

F.25. Listing all events

  1. (ev)list
    Expected: List all added social events in the Event Schedule.

F.26. Editing a social event

  1. Edits a social event while all social events are listed

    1. Prerequisites: List all social events using the (ev)list command. Multiple social events in the list.

    2. Test case: (ev)edit 1 d/2020-04-09 11:00 h/2
      Expected: Edits the first event in the Event Schedule by changing the timing to 11AM on the 9th of April and the estimated duration to be 2 hours.

    3. Test case: (ev)edit d/DATETIME (where DATETIME is after the current date and time)
      Expected: No social event is edited. Error details shown in the status message.

F.27. Deleting a social event

  1. Deletes a social event while all social events are listed

    1. Prerequisites: List all social events using the (ev)list command. Multiple social events in the list.

    2. Test case: (ev)delete 1
      Expected: Deletes the first social event in the Event Schedule.

    3. Test case: (ev)delete x (where x is larger than the size of Event Schedule)
      Expected: No social event is deleted. Error details shown in the status message.

end::manual[]