By: Team Naggy Joel Since: Mar 2020 Licence: MIT
- 1. Setting up
- 2. Design
- 3. Implementation
- 4. Documentation
- 5. Testing
- 6. Dev Ops
- Appendix A: Product Scope
- Appendix B: User Stories
- Appendix C: Use Cases
- Appendix D: Non Functional Requirements
- Appendix E: Glossary
- Appendix F: Instructions for Manual Testing
- F.1. Launch and Shutdown
- F.2. Adding a person
- F.3. Deleting a person
- F.4. Editing a person
- F.5. Adding additional information to a person
- F.6. Editing additional information for a person
- F.7. Deleting additional information of a person
- F.8. Finding a specific contact/specific set of contacts
- F.9. Retrieving a specific contact and view in full details
- F.10. List contacts with upcoming birthdays
- F.11. Adding a restaurant
- F.12. List all restaurants saved
- F.13. Editing a restaurant
- F.14. Deleting a restaurant
- F.15. Adding food note(s) to a restaurant
- F.16. Editing food note(s) of a restaurant
- F.17. Deleting food note(s) of a restaurant
- F.18. Search for restaurants based on a number of criteria
- F.19. Adding an assignment
- F.20. List current assignments
- F.21. Deleting an assignment
- F.22. Editing an assignment
- F.23. Generating schedule
- F.24. Adding a social event
- F.25. Listing all events
- F.26. Editing a social event
- F.27. Deleting a social event
1. Setting up
Refer to the guide here.
2. Design
2.1. Architecture
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.
|
-
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.
Each of the four components
-
Defines its API in an
interfacewith the same name as the Component. -
Exposes its functionality using a
{Component Name}Managerclass.
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.
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.
delete 1 commandThe sections below give more details of each component.
2.2. 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
Logiccomponent. -
Listens for changes to
Modeldata so that the UI can be updated with the modified data.
2.3. Logic component
API :
Logic.java
-
Logicuses theAddressBookParserclass to parse the user command. -
This results in a
Commandobject which is executed by theLogicManager. -
The command execution can affect the
Model(e.g. adding a person). -
The result of the command execution is encapsulated as a
CommandResultobject which is passed back to theUi. -
In addition, the
CommandResultobject can also instruct theUito 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.
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
API : Model.java
The Model,
-
stores a
UserPrefobject 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.
|
2.5. Storage component
API : Storage.java
The Storage component,
-
can save
UserPrefobjects 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).
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.
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.
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.
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.
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:
-
The
ScheduleCommandwill retrieve thefilteredAssignmentsfrom theModelcomponent. -
The
ScheduleListwill then be initialized to have a size equals to theNUM_DAYSqueried by the user, which in this example is5since the user typed(st)schedule n/5.
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:
-
The
StatusandDeadlineof theAssignmentwill be retrieved. -
If
Statusis uncompleted andDeadlineis not over,Workloadwill be distributed.
Fig 7. Sequence Diagram showing the process of generating the schedule
As shown in Fig 8 below, for each uncompleted Assignment:
-
Workloadis retrieved and distributed across several days, from query date to deadline, incrementally so as to generate a balanced schedule. -
The final allocation of hours, including amount unscheduled, is recorded and the
Assignmentwill be recorded as adueAssignmentif its deadline falls within the range of days queried.
Fig 8 Sequence Diagram showing how an uncompleted Assignment is handled
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.
-
Assignmentdue on query date: The amount of time that can be allocated to the assignment will be capped at the amount of time available before theDeadline. -
Assignmentnot due on query date: Incremental distribution ofWorkloadstarting 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.
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 deadlinefor 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.
The following sequence diagram shows how the get operation works within the Logic component:
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:
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.
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.
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 keywordsfriendsandcolleagueswould to go to the Tag Predicate while the keywordNUSwould 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
/tprefix 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.
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.
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
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.
-
Step 2: Suppose the user executes
(rt)add n/KFC l/East v/Noto 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 duplicatingm0, pushing the duplicate into the undo stack, and then making thecurrentModelpointer point to the top of the stack. All changes will then be made to this new duplicate, with the previous statem0intact at the bottom of the undo stack. The redo stack still remains empty.
-
Step 3: Now, suppose the user executes the
undocommand. TheModelManagerwill simply push the current statem1into the redo stack, and make the current state pointer point to the resultant top element in the undo stackm0, 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.
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
redocommand, the application will simply push the top statem1in the redo stack into the undo stack, and make the current state pointer point to the resultant top state in the undo stack again.
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
redocommand, 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.
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:
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)listand 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
undofor commands such as(rt)listonly 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
undooperation)-
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
logLevelsetting in the configuration file (See Section 3.10, “Configuration”) -
The
Loggerfor a class can be obtained usingLogsCenter.getLogger(Class)which will log messages according to the specified logging level -
Currently log messages are output through:
Consoleand to a.logfile.
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
-
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.
-
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
-
User requests to list out all upcoming social events.
-
Naggy Joel lists out all upcoming social events, displaying the dates and times of each event.
-
User chooses the event for which he wants to find a restaurant for and notes down the time and location.
-
User searches for restaurants based on the location of the event.
-
Naggy Joel lists out all restaurants that match the given location.
-
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
-
User requests to know his schedule for the upcoming period (can be the next day, week or month)
-
Naggy Joel generates and displays the user’s schedule for the upcoming period.
-
User chooses a period of free time as shown by Naggy Joel.
-
User creates social event and inputs just the description of social event.
-
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
-
User requests to list out all assignments with upcoming deadlines.
-
Naggy Joel displays a list of all assignments with upcoming deadlines.
-
User chooses the assignment which has been completed.
-
Naggy Joel marks the indicated assignment as completed.
Use case ends.
Use case: Keeping track of birthdays
MSS
-
User requests to list out all upcoming birthdays.
-
Naggy Joel displays a list of birthdays within the next 5 days (including current day), with the name, date and remarks.
-
User views the remarks of the contact to decide on a suitable gift.
Use case ends.
Appendix D: Non Functional Requirements
-
The final product is a result of evolving/enhancing/morphing the given code base.
-
The final product targets users who can type fast and prefer typing over other means of input.
-
The final product should be for a single user.
-
The product is developed incrementally over the project duration.
-
The data should be stored locally and should be in a human editable text file.
-
The data cannot be stored in a DBMS
-
The software should follow the Object-Oriented paradigm primarily.
-
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.
-
The software should work on a computer that has version 11 of Java installed.
-
The software should work without requiring an installer.
-
The software should not depend on a remote server.
-
The use of third-party frameworks is subject to approval by the module administrators
-
The file size of deliverables should not exceed 100MB for the JAR file and 15MB/file for the PDF files
-
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.
-
Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
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
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
tag::manual[]
F.2. Adding a person
-
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
-
Deleting a person while all persons are listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
Test case:
(ab)delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. -
Test case:
(ab)delete 0
Expected: No person is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
(ab)delete,(ab)delete x(where x is larger than the list size)
Expected: Similar to previous.
-
-
Deleting a person while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
Editing a person while all persons listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
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.
-
-
Editing a person while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
Adds note(s) to a person while all persons listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
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.
-
-
Add note(s) to a person while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
Editing an existing note of person while all persons listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
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. -
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. -
Other incorrect commands to try:
(ab)editnote 2 l/aaa i/Likes cats(where line number is not an integer)
Expected: Similar to previous
-
-
Editing an existing note of a person while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
Delete note(s) of a person while all persons listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
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. -
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. -
Other incorrect commands to try:
(ab)deletenote 2 l/2 l/aaa(where line number is not an integer)
Expected: Similar to previous
-
-
Editing a person while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
Finding person(s) by organization, name or tag.
-
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
-
Retrieves a person contact while all persons listed
-
Prerequisites: List all persons using the
(ab)listcommand. Multiple persons in the list. -
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. -
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.
-
-
Retrieves a person contact while finding contacts that meet certain criteria
-
Prerequisites: List subset of contacts using the
(ab)findcommand. Persons who meet the criteria are listed. -
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
-
All persons are listed
-
(ab)birthday
Expected: All contacts with birthdays in the next 5 days (current day included) should be listed.
-
F.11. Adding a restaurant
-
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
-
(rt)list
Expected: All restaurants added should be displayed.
F.13. Editing a restaurant
-
Editing a restaurant while all restaurants are listed
-
Prerequisites: List all restaurants using the
(rt)listcommand. Multiple restaurants in the list. -
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".
-
-
Editing a restaurant while finding restaurants that meet certain criteria
-
Prerequisites: List subset of restaurants using the
(rt)findcommand. Restaurants that meet the criteria are listed. -
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
-
Deletes a restaurant while all restaurants are listed
-
Prerequisites: List all restaurants using the
(rt)listcommand. Multiple restaurants in the list. -
Test case:
(rt)delete 2
Expected: Deletes the second restaurant in the restaurant list. Details of the deleted restaurant shown in the status message. -
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.
-
-
Deleting a restaurant while finding restaurants that meet certain criteria
-
Prerequisites: List subset of restaurants using the
(rt)findcommand. Restaurants that meet the criteria are listed. -
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
-
Add food note(s) to a restaurant while all restaurants are listed
-
Prerequisites: List all restaurants using the
(rt)listcommand. Multiple restaurants in the list. -
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
-
Edit food note(s) to a restaurant while all restaurants are listed
-
Prerequisites: List all restaurants using the
(rt)listcommand. Multiple restaurants in the list. -
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. -
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
-
Delete food note(s) to a restaurant while all restaurants are listed
-
Prerequisites: List all restaurants using the
(rt)listcommand. Multiple restaurants in the list. -
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. -
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
-
(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
-
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. -
Test case:
(st)add t/CS2105 lab d/DEADLINE e/5(whereDEADLINEis before the current date and time)
Expected: No assignment is added. Error details shown in the status message.
F.20. List current assignments
-
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. -
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. -
Test case:
(st)list -d -e
Expected: Assignments will not be sorted. Error details shown in the status message.
F.21. Deleting an assignment
-
Deletes an assignment while all assignments are listed
-
Prerequisites: List all assignments using the
(st)listcommand. Multiple assignments in the list. -
Test case:
(st)delete 1
Expected: Deletes the first assignment in the Schoolwork Tracker. Details of the deleted assignment shown in the status message. -
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
-
Edits an assignment while all assignments are listed
-
Prerequisites: List all assignments using the
(st)listcommand. Multiple assignments in the list. -
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. -
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. -
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. -
Test case:
(st)edit d/DEADLINE(whereDEADLINEis before the current date and time)
Expected: No assignment is edited. Error details shown in the status message. -
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
-
Generates the user’s schedule
-
Prerequisites: There are assignments added to the SchoolworkTracker
-
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. -
Test case:
(st)schedule n/-1
Expected: No schedule is displayed. Error details shown in the status message.
-
F.24. Adding a social event
-
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". -
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
-
(ev)list
Expected: List all added social events in the Event Schedule.
F.26. Editing a social event
-
Edits a social event while all social events are listed
-
Prerequisites: List all social events using the
(ev)listcommand. Multiple social events in the list. -
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. -
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
-
Deletes a social event while all social events are listed
-
Prerequisites: List all social events using the
(ev)listcommand. Multiple social events in the list. -
Test case:
(ev)delete 1
Expected: Deletes the first social event in the Event Schedule. -
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[]
