diff --git a/README.md b/README.md
index 0f4f568095..b944ffdcef 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1 @@
-# Spring Boot Recipe Application
-
-[![CircleCI](https://circleci.com/gh/springframeworkguru/spring5-recipe-app.svg?style=svg)](https://circleci.com/gh/springframeworkguru/spring5-recipe-app)
-
-This repository is for an example application built in my Spring Framework 5 - Beginner to Guru
-
-You can learn about my Spring Framework 5 Online course [here.](https://go.springframework.guru/spring-framework-5-online-course)
\ No newline at end of file
+# Spring Boot Recipe Application
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 25bb466d7f..c419c689b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,9 +2,9 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
+
 	<groupId>guru.springframework</groupId>
 	<artifactId>spring5-recipe-app</artifactId>
-
 	<version>0.0.1-SNAPSHOT</version>
 	<packaging>jar</packaging>
 
@@ -48,6 +48,10 @@
 			<artifactId>h2</artifactId>
 			<scope>runtime</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-test</artifactId>
diff --git a/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java b/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java
new file mode 100644
index 0000000000..b6951f9b6f
--- /dev/null
+++ b/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java
@@ -0,0 +1,212 @@
+package guru.springframework.bootstrap;
+
+import guru.springframework.domain.*;
+import guru.springframework.repositories.CategoryRepository;
+import guru.springframework.repositories.RecipeRepository;
+import guru.springframework.repositories.UnitOfMeasureRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Created by jt on 6/13/17.
+ */
+@Slf4j
+@Component
+public class RecipeBootstrap implements ApplicationListener<ContextRefreshedEvent> {
+
+    private final CategoryRepository categoryRepository;
+    private final RecipeRepository recipeRepository;
+    private final UnitOfMeasureRepository unitOfMeasureRepository;
+
+    public RecipeBootstrap(CategoryRepository categoryRepository, RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) {
+        this.categoryRepository = categoryRepository;
+        this.recipeRepository = recipeRepository;
+        this.unitOfMeasureRepository = unitOfMeasureRepository;
+    }
+
+    @Override
+    @Transactional
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        recipeRepository.saveAll(getRecipes());
+        log.debug("Loading boostrap data");
+    }
+
+    private List<Recipe> getRecipes() {
+
+        List<Recipe> recipes = new ArrayList<>(2);
+
+        //get UOMs
+        Optional<UnitOfMeasure> eachUomOptional = unitOfMeasureRepository.findByDescription("Each");
+
+        String uOMNotFound = "Expected UOM Not Found";
+        if(!eachUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        Optional<UnitOfMeasure> tableSpoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon");
+
+        if(!tableSpoonUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        Optional<UnitOfMeasure> teaSpoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon");
+
+        if(!teaSpoonUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        Optional<UnitOfMeasure> dashUomOptional = unitOfMeasureRepository.findByDescription("Dash");
+
+        if(!dashUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        Optional<UnitOfMeasure> pintUomOptional = unitOfMeasureRepository.findByDescription("Pint");
+
+        if(!pintUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        Optional<UnitOfMeasure> cupsUomOptional = unitOfMeasureRepository.findByDescription("Cup");
+
+        if(!cupsUomOptional.isPresent()){
+            throw new RuntimeException(uOMNotFound);
+        }
+
+        //get optionals
+        UnitOfMeasure eachUom = eachUomOptional.get();
+        UnitOfMeasure tableSpoonUom = tableSpoonUomOptional.get();
+        UnitOfMeasure teapoonUom = tableSpoonUomOptional.get();
+        UnitOfMeasure dashUom = dashUomOptional.get();
+        UnitOfMeasure pintUom = pintUomOptional.get();
+        UnitOfMeasure cupsUom = cupsUomOptional.get();
+
+        //get Categories
+        Optional<Category> americanCategoryOptional = categoryRepository.findByDescription("American");
+
+        if(!americanCategoryOptional.isPresent()){
+            throw new RuntimeException("Expected Category Not Found");
+        }
+
+        Optional<Category> mexicanCategoryOptional = categoryRepository.findByDescription("Mexican");
+
+        if(!mexicanCategoryOptional.isPresent()){
+            throw new RuntimeException("Expected Category Not Found");
+        }
+
+        Category americanCategory = americanCategoryOptional.get();
+        Category mexicanCategory = mexicanCategoryOptional.get();
+
+        //Yummy Guac
+        Recipe guacRecipe = new Recipe();
+        guacRecipe.setDescription("Perfect Guacamole");
+        guacRecipe.setPrepTime(10);
+        guacRecipe.setCookTime(0);
+        guacRecipe.setDifficulty(Difficulty.EASY);
+        guacRecipe.setDirections("1 Cut avocado, remove flesh: Cut the avocados in half. Remove seed. Score the inside of the avocado with a blunt knife and scoop out the flesh with a spoon" +
+                "\n" +
+                "2 Mash with a fork: Using a fork, roughly mash the avocado. (Don't overdo it! The guacamole should be a little chunky.)" +
+                "\n" +
+                "3 Add salt, lime juice, and the rest: Sprinkle with salt and lime (or lemon) juice. The acid in the lime juice will provide some balance to the richness of the avocado and will help delay the avocados from turning brown.\n" +
+                "Add the chopped onion, cilantro, black pepper, and chiles. Chili peppers vary individually in their hotness. So, start with a half of one chili pepper and add to the guacamole to your desired degree of hotness.\n" +
+                "Remember that much of this is done to taste because of the variability in the fresh ingredients. Start with this recipe and adjust to your taste.\n" +
+                "4 Cover with plastic and chill to store: Place plastic wrap on the surface of the guacamole cover it and to prevent air reaching it. (The oxygen in the air causes oxidation which will turn the guacamole brown.) Refrigerate until ready to serve.\n" +
+                "Chilling tomatoes hurts their flavor, so if you want to add chopped tomato to your guacamole, add it just before serving.\n" +
+                "\n" +
+                "\n" +
+                "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvpiV9Sd");
+
+        Notes guacNotes = new Notes();
+        guacNotes.setRecipeNotes("For a very quick guacamole just take a 1/4 cup of salsa and mix it in with your mashed avocados.\n" +
+                "Feel free to experiment! One classic Mexican guacamole has pomegranate seeds and chunks of peaches in it (a Diana Kennedy favorite). Try guacamole with added pineapple, mango, or strawberries.\n" +
+                "The simplest version of guacamole is just mashed avocados with salt. Don't let the lack of availability of other ingredients stop you from making guacamole.\n" +
+                "To extend a limited supply of avocados, add either sour cream or cottage cheese to your guacamole dip. Purists may be horrified, but so what? It tastes great.\n" +
+                "\n" +
+                "\n" +
+                "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvoun5ws");
+
+        guacRecipe.setNotes(guacNotes);
+
+        //very redundent - could add helper method, and make this simpler
+        guacRecipe.addIngredient(new Ingredient("ripe avocados", new BigDecimal(2), eachUom));
+        guacRecipe.addIngredient(new Ingredient("Kosher salt", new BigDecimal(".5"), teapoonUom));
+        guacRecipe.addIngredient(new Ingredient("fresh lime juice or lemon juice", new BigDecimal(2), tableSpoonUom));
+        guacRecipe.addIngredient(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2), tableSpoonUom));
+        guacRecipe.addIngredient(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2), eachUom));
+        guacRecipe.addIngredient(new Ingredient("Cilantro", new BigDecimal(2), tableSpoonUom));
+        guacRecipe.addIngredient(new Ingredient("freshly grated black pepper", new BigDecimal(2), dashUom));
+        guacRecipe.addIngredient(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"), eachUom));
+
+        guacRecipe.getCategories().add(americanCategory);
+        guacRecipe.getCategories().add(mexicanCategory);
+
+        //add to return list
+        recipes.add(guacRecipe);
+
+        //Yummy Tacos
+        Recipe tacosRecipe = new Recipe();
+        tacosRecipe.setDescription("Spicy Grilled Chicken Taco");
+        tacosRecipe.setCookTime(9);
+        tacosRecipe.setPrepTime(20);
+        tacosRecipe.setDifficulty(Difficulty.MODERATE);
+
+        tacosRecipe.setDirections("1 Prepare a gas or charcoal grill for medium-high, direct heat.\n" +
+                "2 Make the marinade and coat the chicken: In a large bowl, stir together the chili powder, oregano, cumin, sugar, salt, garlic and orange zest. Stir in the orange juice and olive oil to make a loose paste. Add the chicken to the bowl and toss to coat all over.\n" +
+                "Set aside to marinate while the grill heats and you prepare the rest of the toppings.\n" +
+                "\n" +
+                "\n" +
+                "3 Grill the chicken: Grill the chicken for 3 to 4 minutes per side, or until a thermometer inserted into the thickest part of the meat registers 165F. Transfer to a plate and rest for 5 minutes.\n" +
+                "4 Warm the tortillas: Place each tortilla on the grill or on a hot, dry skillet over medium-high heat. As soon as you see pockets of the air start to puff up in the tortilla, turn it with tongs and heat for a few seconds on the other side.\n" +
+                "Wrap warmed tortillas in a tea towel to keep them warm until serving.\n" +
+                "5 Assemble the tacos: Slice the chicken into strips. On each tortilla, place a small handful of arugula. Top with chicken slices, sliced avocado, radishes, tomatoes, and onion slices. Drizzle with the thinned sour cream. Serve with lime wedges.\n" +
+                "\n" +
+                "\n" +
+                "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvtrAnNm");
+
+        Notes tacoNotes = new Notes();
+        tacoNotes.setRecipeNotes("We have a family motto and it is this: Everything goes better in a tortilla.\n" +
+                "Any and every kind of leftover can go inside a warm tortilla, usually with a healthy dose of pickled jalapenos. I can always sniff out a late-night snacker when the aroma of tortillas heating in a hot pan on the stove comes wafting through the house.\n" +
+                "Today’s tacos are more purposeful – a deliberate meal instead of a secretive midnight snack!\n" +
+                "First, I marinate the chicken briefly in a spicy paste of ancho chile powder, oregano, cumin, and sweet orange juice while the grill is heating. You can also use this time to prepare the taco toppings.\n" +
+                "Grill the chicken, then let it rest while you warm the tortillas. Now you are ready to assemble the tacos and dig in. The whole meal comes together in about 30 minutes!\n" +
+                "\n" +
+                "\n" +
+                "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvu7Q0MJ");
+
+        tacosRecipe.setNotes(tacoNotes);
+
+        tacosRecipe.addIngredient(new Ingredient("Ancho Chili Powder", new BigDecimal(2), tableSpoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Dried Oregano", new BigDecimal(1), teapoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Dried Cumin", new BigDecimal(1), teapoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Sugar", new BigDecimal(1), teapoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Salt", new BigDecimal(".5"), teapoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Clove of Garlic, Choppedr", new BigDecimal(1), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("finely grated orange zestr", new BigDecimal(1), tableSpoonUom));
+        tacosRecipe.addIngredient(new Ingredient("fresh-squeezed orange juice", new BigDecimal(3), tableSpoonUom));
+        tacosRecipe.addIngredient(new Ingredient("Olive Oil", new BigDecimal(2), tableSpoonUom));
+        tacosRecipe.addIngredient(new Ingredient("boneless chicken thighs", new BigDecimal(4), tableSpoonUom));
+        tacosRecipe.addIngredient(new Ingredient("small corn tortillasr", new BigDecimal(8), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("packed baby arugula", new BigDecimal(3), cupsUom));
+        tacosRecipe.addIngredient(new Ingredient("medium ripe avocados, slic", new BigDecimal(2), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("radishes, thinly sliced", new BigDecimal(4), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("cherry tomatoes, halved", new BigDecimal(".5"), pintUom));
+        tacosRecipe.addIngredient(new Ingredient("red onion, thinly sliced", new BigDecimal(".25"), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("Roughly chopped cilantro", new BigDecimal(4), eachUom));
+        tacosRecipe.addIngredient(new Ingredient("cup sour cream thinned with 1/4 cup milk", new BigDecimal(4), cupsUom));
+        tacosRecipe.addIngredient(new Ingredient("lime, cut into wedges", new BigDecimal(4), eachUom));
+
+        tacosRecipe.getCategories().add(americanCategory);
+        tacosRecipe.getCategories().add(mexicanCategory);
+
+        recipes.add(tacosRecipe);
+        return recipes;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/guru/springframework/controllers/IndexController.java b/src/main/java/guru/springframework/controllers/IndexController.java
new file mode 100644
index 0000000000..dee7db03c6
--- /dev/null
+++ b/src/main/java/guru/springframework/controllers/IndexController.java
@@ -0,0 +1,27 @@
+package guru.springframework.controllers;
+
+import guru.springframework.services.RecipeService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Slf4j
+@Controller
+public class IndexController {
+
+    private final RecipeService recipeService;
+
+    public IndexController(RecipeService recipeService) {
+        this.recipeService = recipeService;
+    }
+
+    @RequestMapping({"", "/", "/index"})
+    public String getIndexPage(Model model) {
+        log.debug("getting index page");
+
+        model.addAttribute("recipes", recipeService.getRecipes());
+
+        return "index";
+    }
+}
diff --git a/src/main/java/guru/springframework/domain/Category.java b/src/main/java/guru/springframework/domain/Category.java
new file mode 100644
index 0000000000..4291db4c64
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Category.java
@@ -0,0 +1,21 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import lombok.*;
+
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(exclude = {"recipes"})
+@Entity
+public class Category {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    private String description;
+
+    @ManyToMany(mappedBy = "categories")
+    private Set<Recipe> recipes;
+
+}
diff --git a/src/main/java/guru/springframework/domain/Difficulty.java b/src/main/java/guru/springframework/domain/Difficulty.java
new file mode 100644
index 0000000000..f375554a10
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Difficulty.java
@@ -0,0 +1,9 @@
+package guru.springframework.domain;
+
+public enum Difficulty {
+
+    EASY,
+    MODERATE,
+    IND_OF_HARD,
+    HARD
+}
diff --git a/src/main/java/guru/springframework/domain/Ingredient.java b/src/main/java/guru/springframework/domain/Ingredient.java
new file mode 100644
index 0000000000..fb56be5caa
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Ingredient.java
@@ -0,0 +1,41 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+@Data
+@EqualsAndHashCode(exclude = {"recipe"})
+@Entity
+public class Ingredient {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    private String description;
+    private BigDecimal amount;
+
+    @OneToOne(fetch = FetchType.EAGER)
+    private UnitOfMeasure uom;
+
+    @ManyToOne
+    private Recipe recipe;
+
+    public Ingredient() {
+    }
+
+    public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom) {
+        this.description = description;
+        this.amount = amount;
+        this.uom = uom;
+    }
+
+    public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom, Recipe recipe) {
+        this.description = description;
+        this.amount = amount;
+        this.uom = uom;
+        this.recipe = recipe;
+    }
+}
diff --git a/src/main/java/guru/springframework/domain/Notes.java b/src/main/java/guru/springframework/domain/Notes.java
new file mode 100644
index 0000000000..a0573a2074
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Notes.java
@@ -0,0 +1,25 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import lombok.*;
+
+
+/**
+ * Created by jt on 6/13/17.
+ */
+@Data
+@EqualsAndHashCode(exclude = {"recipe"})
+@Entity
+public class Notes {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @OneToOne
+    private Recipe recipe;
+
+    @Lob
+    private String recipeNotes;
+
+}
diff --git a/src/main/java/guru/springframework/domain/Recipe.java b/src/main/java/guru/springframework/domain/Recipe.java
new file mode 100644
index 0000000000..f4a42bf6fc
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Recipe.java
@@ -0,0 +1,59 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import lombok.Data;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Created by jt on 6/13/17.
+ */
+@Data
+@Entity
+public class Recipe {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    private String description;
+    private Integer prepTime;
+    private Integer cookTime;
+    private Integer servings;
+    private String source;
+    private String url;
+
+    @Lob
+    private String directions;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe")
+    private Set<Ingredient> ingredients = new HashSet<>();
+
+    @Lob
+    private Byte[] image;
+
+    @Enumerated(value = EnumType.STRING)
+    private Difficulty difficulty;
+
+    @OneToOne(cascade = CascadeType.ALL)
+    private Notes notes;
+
+    @ManyToMany
+    @JoinTable(name = "recipe_category ",
+        joinColumns = @JoinColumn(name = "recipe_id"),
+        inverseJoinColumns = @JoinColumn(name = "category_id"))
+    private Set<Category> categories = new HashSet<>();
+
+    public void setNotes(Notes notes) {
+        this.notes = notes;
+        notes.setRecipe(this);
+    }
+
+    public Recipe addIngredient(Ingredient ingredient){
+        ingredient.setRecipe(this);
+        this.ingredients.add(ingredient);
+        return this;
+    }
+
+}
diff --git a/src/main/java/guru/springframework/domain/UnitOfMeasure.java b/src/main/java/guru/springframework/domain/UnitOfMeasure.java
new file mode 100644
index 0000000000..e8ca1e1209
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/UnitOfMeasure.java
@@ -0,0 +1,15 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import lombok.*;
+
+@Data
+@Entity
+public class UnitOfMeasure {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    private String description;
+
+}
diff --git a/src/main/java/guru/springframework/repositories/CategoryRepository.java b/src/main/java/guru/springframework/repositories/CategoryRepository.java
new file mode 100644
index 0000000000..2fca6df4e7
--- /dev/null
+++ b/src/main/java/guru/springframework/repositories/CategoryRepository.java
@@ -0,0 +1,11 @@
+package guru.springframework.repositories;
+
+import guru.springframework.domain.Category;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.Optional;
+
+public interface CategoryRepository extends CrudRepository<Category, Long> {
+
+    Optional<Category> findByDescription(String description);
+}
diff --git a/src/main/java/guru/springframework/repositories/RecipeRepository.java b/src/main/java/guru/springframework/repositories/RecipeRepository.java
new file mode 100644
index 0000000000..c825c7b2b0
--- /dev/null
+++ b/src/main/java/guru/springframework/repositories/RecipeRepository.java
@@ -0,0 +1,9 @@
+package guru.springframework.repositories;
+
+import guru.springframework.domain.Recipe;
+import org.springframework.data.repository.CrudRepository;
+
+public interface RecipeRepository extends CrudRepository<Recipe, Long>{
+
+
+}
diff --git a/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java b/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java
new file mode 100644
index 0000000000..76ca864681
--- /dev/null
+++ b/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java
@@ -0,0 +1,11 @@
+package guru.springframework.repositories;
+
+import guru.springframework.domain.UnitOfMeasure;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.Optional;
+
+public interface UnitOfMeasureRepository extends CrudRepository<UnitOfMeasure, Long> {
+
+    Optional<UnitOfMeasure> findByDescription(String description);
+}
diff --git a/src/main/java/guru/springframework/services/RecipeService.java b/src/main/java/guru/springframework/services/RecipeService.java
new file mode 100644
index 0000000000..fb5d986c6f
--- /dev/null
+++ b/src/main/java/guru/springframework/services/RecipeService.java
@@ -0,0 +1,10 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Recipe;
+
+import java.util.Set;
+
+public interface RecipeService {
+
+    Set<Recipe> getRecipes();
+}
diff --git a/src/main/java/guru/springframework/services/RecipeServiceImpl.java b/src/main/java/guru/springframework/services/RecipeServiceImpl.java
new file mode 100644
index 0000000000..9e5ef9fe1c
--- /dev/null
+++ b/src/main/java/guru/springframework/services/RecipeServiceImpl.java
@@ -0,0 +1,30 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Recipe;
+import guru.springframework.repositories.RecipeRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Slf4j
+@Service
+public class RecipeServiceImpl implements RecipeService{
+
+    private final RecipeRepository recipeRepository;
+
+    public RecipeServiceImpl(RecipeRepository recipeRepository) {
+        this.recipeRepository = recipeRepository;
+    }
+
+    @Override
+    public Set<Recipe> getRecipes() {
+        log.debug("I'm in the service");
+
+        Set<Recipe> recipes = new HashSet<>();
+        recipeRepository.findAll().iterator().forEachRemaining(recipes::add);
+
+        return recipes;
+    }
+}
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 0000000000..85ffa02ea5
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,12 @@
+INSERT INTO category (description) VALUES ('American');
+INSERT INTO category (description) VALUES ('Italian');
+INSERT INTO category (description) VALUES ('Mexican');
+INSERT INTO category (description) VALUES ('Fast Food');
+INSERT INTO unit_of_measure (description) VALUES ('Teaspoon');
+INSERT INTO unit_of_measure (description) VALUES ('Tablespoon');
+INSERT INTO unit_of_measure (description) VALUES ('Cup');
+INSERT INTO unit_of_measure (description) VALUES ('Pinch');
+INSERT INTO unit_of_measure (description) VALUES ('Ounce');
+INSERT INTO unit_of_measure (description) VALUES ('Each');
+INSERT INTO unit_of_measure (description) VALUES ('Dash');
+INSERT INTO unit_of_measure (description) VALUES ('Pint');
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
new file mode 100644
index 0000000000..b34400d395
--- /dev/null
+++ b/src/main/resources/templates/index.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8"/>
+    <title>Recipe Home</title>
+
+    <!-- Latest compiled and minified CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
+          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
+
+    <!-- Latest compiled and minified JavaScript -->
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
+            integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
+            crossorigin="anonymous"></script>
+</head>
+<body>
+
+<div class="container-fluid" style="margin-top: 20px">
+    <div class="row">
+        <div class="col-md-6 col-md-offset-3">
+            <div class="panel panel-primary">
+
+                <div class="panel-heading">
+                    <h1 class="panel-title">My Recipes!</h1>
+                </div>
+                <div class="panel-body">
+                    <div class="table-responsive" th:if="${not #lists.isEmpty(recipes)}">
+                        <table class="table table-hover ">
+                            <thead class="thead-inverse">
+                            <tr>
+                                <th>ID</th>
+                                <th>Description</th>
+                            </tr>
+                            </thead>
+                            <tr th:remove="all">
+                                <td th:text="${recipe.id}">123</td>
+                                <td th:text="${recipe.description}">Tasty Goodnees 1</td>
+                            </tr>
+                            <tr th:remove="all">
+                                <td th:text="${recipe.id}">12333</td>
+                                <td th:text="${recipe.description}">Tasty Goodnees 2</td>
+                            </tr>
+                            <tr th:each="recipe : ${recipes}">
+                                <td th:text="${recipe.id}">334</td>
+                                <td th:text="${recipe.description}">Tasty Goodnees 3</td>
+                            </tr>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/src/test/java/guru/springframework/controllers/IndexControllerTest.java b/src/test/java/guru/springframework/controllers/IndexControllerTest.java
new file mode 100644
index 0000000000..e05ada6b93
--- /dev/null
+++ b/src/test/java/guru/springframework/controllers/IndexControllerTest.java
@@ -0,0 +1,74 @@
+package guru.springframework.controllers;
+
+import guru.springframework.domain.Recipe;
+import guru.springframework.services.RecipeService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.ui.Model;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
+
+
+public class IndexControllerTest {
+
+    @Mock
+    RecipeService recipeService;
+
+    @Mock
+    Model model;
+
+    IndexController controller;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        controller = new IndexController(recipeService);
+    }
+
+    @Test
+    public void testMockMVC() throws Exception {
+        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+        mockMvc.perform(get("/"))
+                .andExpect(status().isOk())
+                .andExpect(view().name("index"));
+    }
+
+    @Test
+    public void getIndexPage() {
+
+        //given
+        Set<Recipe> recipes = new HashSet<>();
+        recipes.add(new Recipe());
+        Recipe recipe = new Recipe();
+        recipe.setId(1L);
+        recipes.add(recipe);
+
+        when(recipeService.getRecipes()).thenReturn(recipes);
+
+        ArgumentCaptor<Set<Recipe>> argumentCaptor = ArgumentCaptor.forClass(Set.class);
+
+        //when
+        String viewName = controller.getIndexPage(model);
+
+        //then
+        assertEquals("index", viewName);
+        verify(recipeService, times(1)).getRecipes();
+        verify(model,times(1)).addAttribute(eq("recipes"), argumentCaptor.capture());
+        Set<Recipe> setInController = argumentCaptor.getValue();
+        assertEquals(2, setInController.size());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/guru/springframework/domain/CategoryTest.java b/src/test/java/guru/springframework/domain/CategoryTest.java
new file mode 100644
index 0000000000..2c38cd3218
--- /dev/null
+++ b/src/test/java/guru/springframework/domain/CategoryTest.java
@@ -0,0 +1,33 @@
+package guru.springframework.domain;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class CategoryTest {
+
+    Category category;
+
+    @Before
+    public void setUp(){
+        category = new Category();
+    }
+
+    @Test
+    public void getId() {
+        Long idValue = 4L;
+
+        category.setId(idValue);
+
+        assertEquals(idValue, category.getId());
+    }
+
+    @Test
+    public void getDescription() {
+    }
+
+    @Test
+    public void getRecipes() {
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java b/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java
new file mode 100644
index 0000000000..dda1870b44
--- /dev/null
+++ b/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java
@@ -0,0 +1,39 @@
+package guru.springframework.repositories;
+
+import guru.springframework.domain.UnitOfMeasure;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Optional;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@DataJpaTest
+public class UnitOfMeasureRepositoryIT {
+
+    @Autowired
+    UnitOfMeasureRepository unitOfMeasureRepository;
+
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    @Test
+    public void findByDescription() throws Exception {
+
+        Optional<UnitOfMeasure> uomOptional = unitOfMeasureRepository.findByDescription("Teaspoon");
+        assertEquals("Teaspoon", uomOptional.get().getDescription());
+    }
+
+    @Test
+    public void findByDescriptionCup() throws Exception {
+
+        Optional<UnitOfMeasure> uomOptional = unitOfMeasureRepository.findByDescription("Cup");
+        assertEquals("Cup", uomOptional.get().getDescription());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/guru/springframework/services/RecipeServiceImplTest.java b/src/test/java/guru/springframework/services/RecipeServiceImplTest.java
new file mode 100644
index 0000000000..6fa5611530
--- /dev/null
+++ b/src/test/java/guru/springframework/services/RecipeServiceImplTest.java
@@ -0,0 +1,45 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Recipe;
+import guru.springframework.repositories.RecipeRepository;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class RecipeServiceImplTest {
+
+    RecipeServiceImpl recipeService;
+
+    @Mock
+    RecipeRepository recipeRepository;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        recipeService = new RecipeServiceImpl(recipeRepository);
+    }
+
+    @Test
+    public void getRecipes() {
+
+        Recipe recipe = new Recipe();
+        HashSet recipesData = new HashSet();
+        recipesData.add(recipe);
+
+        when(recipeRepository.findAll()).thenReturn(recipesData);
+
+        Set<Recipe> recipes = recipeService.getRecipes();
+
+        assertEquals(recipes.size(), 1);
+        verify(recipeRepository, times(1)).findAll();
+
+    }
+}
\ No newline at end of file