Developer Guide
Acknowledgements
- This application is built in fulfillment of the requirements of CS2113.
- Knowledge and ideas are adapted from the CS2113 textbook, as well as SE-EDU textbook.
Table of Contents
- Setting up, getting started
- Design & Implementation
- Architecture
- UI Component
- RecipeList Component
- InputParser Component
- CommandValidator Component
- Storage Component
- Appendix - Requirements
- Appendix - Commands Glossary
- Appendix - Manual Testing
- Appendix - Area of Improvement
Setting up, getting started
Refer to the User guide for how to get started with RecipeIO.
Design & implementation
Architecture

The Architecture Diagram given above explains the high-level design of the application.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
RecipeIO
is in charge of the app launch and shut down.
- At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
- At shut down, it shuts down the other components and invokes cleanup methods where necessary.
The bulk of the app’s work is done by the following five components:
UI
: The UI of the App.
RecipeList
: The command executor and holder of data of the app.
InputParser
: Extracts information from the user input into the command line.
CommandValidator
: The command validator.
Storage
: Reads data from, and writes data to, the hard disk.
The commands
package represents a collection of commands used by RecipeList
.
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
.

UI Component
The API of this component is specified in UI.java

The UI
has a class-level attribute SEPARATOR
, which is a line of dashes that can be used in console output.
The UI
has the following methods
getUserInput
: asks the user for an input through the command line.
sayHi
(class-level): greets the user.
printInstructions
(class-level) : prints a list of accepted commands.
printInvalidCommandWarning
(class-level) : warns the user of an invalid command.
bye
(class-level) : bids farewell to the user.
How the component works:
- Upon starting of the app,
RecipeIO
will create an instance of the UI
class.
- The instance will be asking the user for his or her input, via the
getUserInput
method.
- During the execution of the app, it will also give the user some console feedback.
- For example, the
printInstructions
method is called when the user inputs help
.
RecipeList Component
The API of this component is specified in RecipeList.java

The RecipeList
contains many Recipe
s, which has attributes:
name
: String
cookTime
: int
calories
: int
allergies
: ArrayList
mealCategory
: MealCategory
url
: String
dateAdded
: LocaleDate
How the component works:
- Upon
executeCommand
call, the RecipeList
will identify the command given in the user input (e.g. list
),
- It will then call the corresponding
listRecipes()
method defined in RecipeList
.
- This
listRecipes()
method will first call the isValidListCommand
method in CommandValidator
class.
- If the command is valid, the
ListRecipeCommand.execute()
command is called.
- The reason for such a structure is to allow for command validation before the real execution. A good example is the
find()
command.
- Thus,
RecipeList
contains an intermediate method for each functionality (add, find, delete, so on) , and serves as a command validator.
- Note: these methods have been omitted in the class diagram for brevity.
- In
add()
and delete()
, the saveRecipes()
method is called to save the recipeBook after the modification.
The API of this component is specified in InputParser.java

The InputParser
contains many static methods that are used to make sense of the user’s input. Some important methods are:
parseCommand(userInput)
: String
- gets the command type from the user input. e.g.
add
, delete
parseDetails(userInput)
: String[]
- gets the parameters that the user gave in his or her input.
- for example, if the user inputs
find kw pasta
, the method will return ["kw", "pasta"]
parseMealCriteria(userInput)
: MealCategory
- checks which meal category the user inputted.
How the component works:
- The
InputParser
methods are called during command validation (see next Section for CommandValidator
implementation)
CommandValidator Component
The API of this component is specified in CommandValidator.java

The CommandValidator
contains many static methods that are used to validate the user’s input. Some important methods are:
isValidAddCommand(userInput)
: boolean
isValidDetailCommand(userInput)
: boolean
isValidDeleteCommand(userInput)
: boolean
isValidFindCommand(userInput)
: boolean
For example the isValidDeleteCommand
will return false
if one of the following happens.
- the user does not input an index to find. e.g.
delete
- the user’s inputted index is not a integer. e.g.
delete abc
- the user inputs an index that is out of range. e.g.
delete -1
, or delete 10
when there are only 3 recipes.
How the component works:
- The
CommandValidator
methods are called by methods in the RecipeList
component to verify the user’s input.
- Methods in
InputParser
are called to make sense of the user’s input.
Storage Component
The API of this component is specified in Storage.java

The Storage
class handles the saving and loading of data file (i.e. the recipe book). Some important methods are:
saveFile(ArrayList<Recipe> recipeList))
: void
loadData()
: void
How the component works:
- Upon start up of
RecipeIO
, an instance of Storage
is created, and the app attempts to read an existing data file via the loadData()
method.
- If no file is found, the application will create one upon execution of
add
command.
- The
list
, add
, and delete
methods in RecipeList
will call the saveFile
method to write into the data file.
Appendix: Requirements
Product scope
Target user profile
Recipe.io is designed to cater to a diverse range of users who share a common need to manage and access a significant number of recipes effectively. Here are key characteristics of our target users:
-
Culinary Professionals:
Chefs, culinary students, and other professionals in the food industry who need to store, organize, and access a wide variety of recipes for their culinary creations.
-
Home Chefs and Cooking Enthusiasts:
Individuals who enjoy cooking and experimenting with new recipes at home and wish to expand their culinary repertoire. They appreciate a tool that helps them organize and revisit their favorite recipes.
-
Fast Typers:
Users who are proficient with keyboard use and prefer typing over mouse interactions, making them ideal users of a CLI-based application. They value the efficiency and speed that CLI programs offer.
-
Individuals with Dietary Restrictions:
Users who need to manage dietary restrictions due to health reasons, allergies, or personal choices. They benefit from the ability to filter and search recipes based on specific ingredients or allergens.
-
Tech-Savvy Recipe Collectors:
Users who frequently collect recipes from various online sources and prefer a digital solution to manage and categorize these recipes easily. They require a tool that allows quick access and efficient management of a digital recipe collection.
-
Educational Users:
Cooking instructors and students who use recipes as a teaching and learning tool in culinary courses. They need to access and provide recipes easily during classes and practical sessions.
-
Meal Planners and Preppers:
Individuals who plan meals for the week or month and need to organize recipes based on meal types, ingredients, or nutritional information to streamline their meal preparation process.
Value proposition
- The user will be able to add, access, and list recipes.
- He can also filter recipes based on allergies (i.e. excluding a certain ingredient)
- The saved recipes will be loaded in a recipe text file for easy access and sharing with friends.
- The user can put the recipes into different meal categories.
- The user can view his recipes in different sorted orders.
- The user can easily access details of a particular recipe.
User Stories
Version |
As a … |
I want to … |
So that I can … |
v1.0 |
new user |
see usage instructions |
refer to them when I forget how to use the application |
v1.0 |
user |
add a recipe |
curate my own unique recipes for future use |
v1.0 |
user |
delete a recipe |
remove any outdated or unimportant recipes |
v1.0 |
user |
view all of my recipes |
access my recipes and see how many I have easily |
v2.0 |
user |
find a recipe by name |
locate a recipe without having to go through the entire list |
v2.0 |
foodie |
save and load recipes |
share recipes with friends conveniently |
v2.0 |
user |
find recipes without a certain ingredient |
save time finding recipes that I can eat (leave out allergies) |
v2.0 |
user |
view details of a particular recipe |
learn more about the recipe that I may have forgotten |
v2.0 |
user |
find a recipe by date |
find a recipe from a particular day if I don’t remember its name |
v2.1 |
user |
see my recipe list in a certain way |
make decisions quicker |
v2.1 |
user |
find a recipe by url |
access recipes from a certain website easily |
Use cases
(For all use cases below, the System is the RecipeIO
and the Actor is the user
, unless specified otherwise)
Use case: Delete a recipe
- User requests to list recipes
- RecipeIO shows a list of recipes
- User requests to delete a specific recipe in the list
- RecipeIO deletes the recipe and confirms the deletion to the user.
Use case ends.
Use case: Add a recipe
- User provides details for a new recipe using the
add
command format.
- RecipeIO validates the input data.
- If the data is valid, RecipeIO stores the new recipe and confirms the addition to the user.
- If the data is invalid, RecipeIO informs the user about the validation errors and requests correct data.
Use case ends.
Use case: Find recipes by keyword
- User inputs a keyword using the
find kw [KEYWORD]
command.
- RecipeIO searches for recipes containing the keyword in their names / descriptions.
- RecipeIO displays the list of matching recipes.
- If no recipes match, RecipeIO informs the user that no recipes were found.
Use case ends.
Use case: Find recipes by date
- User inputs a date using the
find date [YYYY-MM-DD]
command.
- RecipeIO searches for recipes added on the specified date.
- RecipeIO displays the list of recipes added on that date.
- If no recipes match the specified date, RecipeIO informs the user that no recipes were added on that date.
Use case ends.
Use case: Find recipes by URL
- User inputs a URL using the
find url [URL]
command.
- RecipeIO searches for recipes that include the specified URL or match parts of the URL in their stored URL data.
- RecipeIO displays the list of recipes that match the URL criteria.
- If no recipes match the specified URL, RecipeIO informs the user that no recipes were found with that URL.
Use case ends.
Use case: Find recipes by meal category
- User inputs a meal category using the
find meal [MEAL_CATEGORY]
command.
- RecipeIO searches for recipes that are part of the specified meal category.
- RecipeIO displays the list of recipes that match the URL criteria.
- If no recipes match the specified meal category, RecipeIO informs the user that no recipes were found with that URL.
Use case ends.
Use case: Filter recipes by allergy
- User specifies an allergy using the
filter [ALLERGY]
command.
- RecipeIO filters the recipes to exclude any that contain the specified allergy.
- RecipeIO displays the list of filtered recipes.
- If all recipes contain the allergy, RecipeIO informs the user that no suitable recipes were found.
Use case ends.
Use case: List all recipes
- User requests to view all recipes using the
list
command.
- RecipeIO retrieves all recipes from storage.
- RecipeIO displays the recipes in the order they were added or sorted according to any specified criteria.
- If no recipes exist, RecipeIO informs the user that the recipe book is empty.
Use case ends.
Use case: Exit the application
- User issues the
exit
command to close the application.
- RecipeIO saves any changes made during the session.
- RecipeIO closes the application and confirms closure to the user.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed.
Appendix: Commands Glossary
Note: []
denote mandatory parameters, while {}
denote optional paramters.
- add [NAME, MINUTES, KCALS, ALLERGIES, CATEGORY, URL] - This is the command a user can call to add a recipe.
- help - This shows the user all the available commands.
- list {SORT_TYPE} - This lists out a users recipebook for them.
- detail [RECIPE NUMBER] - This allows you to view creation details of a certain recipe.
- delete [RECIPE NUMBER] - This deletes a recipe at a given valid index. If not valid, it will return an error message.
- find kw [KEYWORD] - This finds recipes with a user-given keyword.
- find date [YYYY-MM-DD] - This finds recipes added on a user-given date. The date is auto-added when adding.
- filter allergy [KEYWORD] - This filters out recipes with a certain ingredient/allergy.
-
exit - This is the command to leave the program.
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on;
testers are expected to do more exploratory testing.</div>
{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
Adding a Recipe
- Test case:
add pizza, 34, 340, egg/nut/dairy/red meat, dinner, www.food.com
- Expected: The specified recipe is successfully added to the recipe list.
- Console output: Displays a brief description of the added recipe along with the total number of recipes in the list.
- Test case:
add pizza, 34, 340, egg/nut/dairy/red meat, dinner
- Expected: The recipe is not added due to a missing required parameter.
- Console output: Prompts the user to provide all 6 required parameters.
- Test case:
add pizza, abc, def, egg/nut/dairy/red meat, dinner, www.food.com
- Expected: The recipe is not added because the input types for cook time and calories are incorrect.
- Console output: Informs the user that integers are required for cook time and calorie fields.
- Test case:
add pizza, 34, 340, egg/nut/dairy/red meat, capybara, www.food.com
- Expected: The recipe is not added due to an unrecognized meal category.
- Console output: Requests the user to select a valid meal category from the provided options: breakfast, lunch, dinner, appetizer, and dessert.
- Test case:
add pizza, 34, 340, egg/nut/dairy/red meat, lunch, food.com
- Expected: The recipe is not added because the URL lacks the required protocol.
- Console output: Urges the user to include a proper protocol in the URL with examples.
- Test case:
add pizza, 34, 340, egg/nut/dairy/red meat, lunch, www.food
- Expected: The recipe is not added due to an invalid domain or top-level domain in the URL.
- Console output: Advises the user to use valid domain names with examples.
- Test case:
add pizza 34, 340, egg/nut/dairy/red meat, lunch, www.food
- Expected: The recipe is not added because a comma is missing, leading to incorrect parameter parsing.
- Console output: Alerts the user to provide all 6 parameters correctly and suggests checking for missing commas.
Deleting a Recipe
Prerequisites: Ensure that multiple recipes are listed using the list
command.
- Test case:
delete 1
- Expected: The first recipe in the list is successfully deleted.
- Console output: Confirms which recipe was deleted with a brief description.
- Test case:
delete 0
- Expected: No recipe is deleted because the index provided is out of bounds.
- Console output: Reminds the user to enter a number within the range of existing recipe numbers.
- Test case:
delete xyz
- Expected: No recipe is deleted as the input is not an integer.
- Console output: Instructs the user to input an integer value.
- Test case:
delete
- Expected: No recipe is deleted as no index is provided.
- Console output: Directs the user to provide an index for the delete command.
Show the recipe list
Prerequisites: List all recipes using the list
command. Multiple recipes in the list.
- Test case:
list sortname sortdate
- Expected: The recipe list is not shown due to having extra details aside from
SORT_TYPE
- Console output: Reports that there are redundant details for the command
- Test case:
list srt
- Expected: The recipe list is not shown due to the incorrect
SORT_TYPE
.
- Console output: Reports that
SORT_TYPE
is incorrect.
- Console output: Also display available options for
SORT_TYPE
to the user.
- Test case:
list sortname
- Expected: The recipes in recipe list are sorted according to their name.
- Console output: Display list of recipes organised according to their recipe name in alphabetical order.
- Test case:
list sortdate
- Expected: The recipes in recipe list are sorted according to the date they were added.
- Console output: Display list of recipes organised according to the date they were added from earliest to latest.
- Test case:
list sortcooktime
- Expected: The recipe list is sorted according to their cook time.
- Console output: Display list of recipes organised according to their cooking time from the shortest.
- Test case:
list sortcalories
- Expected: The recipe list is sorted according to their calories.
- Console output: Display list of recipes organised according to their calories from the lowest.
Showing Details of a Recipe
Prerequisites: Ensure that multiple recipes are listed using the list command, and that each recipe has a unique index/recipe number associated with it.
- Test Case:
detail 1
- Expected: The full details of the first recipe in the list are displayed.
- Console Output: Outputs all details of the first recipe (name, cook time, calories, allergies, category, URL, date added).
- Test Case:
detail 0
- Expected: No details are shown because the index/recipe number provided is out of bounds (since the program is 1-based indexing).
- Console Output: Outputs a message reminding the user to enter a number within the range of existing recipe numbers.
- Test Case:
detail xyz
- Expected: No details are shown as the input is not an integer.
- Console Output: Outputs a message instructing the user to input an integer value.
- Test Case:
detail
- Expected: No details are shown as no index/recipe number is provided.
- Console Output: Outputs a message directing the user to provide an index/recipe number for the detail command.
Finding a Recipe by Keyword
Prerequisites: Ensure that multiple recipes are listed, including at least one with “soup” in the recipe name.
- Test case:
find kw soup
- Expected: Recipes containing the word “soup” in their names are found and listed.
- Console output: Shows which recipes include the keyword “soup”.
- Test case:
find kw sou
- Expected: No matching recipe is found as the keyword does not exactly match any recipe names.
- Console output: Suggests the user try another keyword or check the existing recipe names for exact matches.
- Test case:
find kw
- Expected: No recipe is found due to the absence of a keyword.
- Console output: Prompts the user to ensure two arguments are entered for the find command.
- Test case:
find kw 1
- Expected: No recipe matches because the keyword is not alphabetical.
- Console output: Reminds the user that the keyword should consist of alphabets only.
Finding a Recipe by Date
Prerequisites: List all recipes, ensuring at least one has a date of 2024-03-30
and none on 2024-01-03
.
- Test case:
find date 2024-03-30
- Expected: Recipes added on
2024-03-30
are successfully found and listed.
- Console output: Displays the recipes added on the specified date.
- Test case:
find date 2024-01-03
- Expected: No recipes are found as no recipes were added on that date, despite the date being valid.
- Console output: Reports that no recipes were added on
2024-01-03
.
- Test case:
find date xyx
- Expected: No recipe is found because the input does not conform to a valid date format.
- Console output: Notifies the user that the date is not valid and suggests using the
YYYY-MM-DD
format.
- Test case:
find date
- Expected: No recipe is found due to the lack of a specified date.
- Console output: Asks the user to ensure that two arguments are entered for the find command.
Finding a recipe by url
Prerequisites: List all recipes using the list
command. Multiple recipes in the list.
At least one recipe with url of www.food.com/fish
but none with url of www.food.net
.
- Test case:
find url www.food.com
- Expected: Matching recipes containing valid urls are given, including
www.food.com/fish
- Console output: Shows the user which recipes match the url of
www.food.com
- Test case:
find url
- Expected: No recipe is found due to the lack of a given url.
- Console output: Asks the user to check that he or she inputted two arguments to the find method.
- Test case:
find url 123
- Expected: No recipe is found due to an invalid url subdomain.
- Console output: Reports to the user that a valid subdomain must be given, with valid url examples given.
- Test case:
find url food.com
- Expected: No recipe is found due to an invalid url subdomain.
- Console output: Reports to the user that a valid subdomain must be given, with valid url examples given.
- Test case:
find url www.food
- Expected: No recipe is found due to an invalid url domain.
- Console output: Reports to the user that a valid domain or TLD must be given, with valid url examples given.
- Test case:
find url www.food.net
- Expected: No matching recipes are found despite a valid url given.
- Console output: Reports that no recipes matches
www.food.net
as a
valid url is given without any matching recipes.
- Test case:
find url www.food.com/fish
- Expected: Recipes matching the whole url including path will be matched, thus excluding
www.food.com
recipes
- Console output: Shows the user which recipes match the url of
www.food.com/fish
Finding a recipe by meal category
Prerequisites: List all recipes using the list
command. There is at least one recipe in the BREAKFAST
meal category, and none in the DINNER
meal category.
- Test case:
find meal BREAKFAST
- Expected: Recipes categorized under BREAKFAST are displayed.
- Console output: Shows the user which recipes are categorized as BREAKFAST.
- Test case:
find meal
- Expected: No recipe is found due to the lack of a specified meal category.
- Console output: Asks the user to check that he or she inputted two arguments to the find method.
- Test case:
find meal breakfast
- Expected: Recipes categorized under BREAKFAST are displayed, showcasing case-insensitivity in category handling.
- Console output: Shows the user which recipes are categorized as BREAKFAST.
- Test case:
find meal snack
- Expected: No recipe is found as “snack” is not a valid meal category.
- Console output: Informs the user that “snack” is not a recognized meal category and displays valid options: GENERAL, BREAKFAST, LUNCH, DINNER, APPETIZER, DESSERT.
- Test case:
find meal DINNER
- Expected: No recipe is found as there are no recipes with
DINNER
as a meal category.
-
Appendix: Area of Improvement
- Having the CommandValidator return the parsed input, if the command is valid.
CommandValidator
evaluates the inputs from the user, but only returns a boolean value of whether the command is valid.
- If the command is valid, there is an additional call to
InputParser
to get the inputs again.
- Recommendation: The
CommandValidator
could return the input together if the command is valid, and null
otherwise.
- Enabling
find
and filter
with various inputs
- Currently, the find and filter only take in one searchable input. Expanding that to include multiple (eg
filter egg dairy
) could increase the potential use case of the app.