diff --git a/pom.xml b/pom.xml
index f056a3def032442e353770477484d031cfdb792b..ab6e21b5ab7c9b5c51f28bba9de9b9fad23bc561 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,17 @@
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>3.16.1</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/requests.http b/requests.http
index d51fde8dc0b81d562777227dd8523f0330788ad3..50ce01e6d355d28e4c09c1c33cab6092a487ed5a 100644
--- a/requests.http
+++ b/requests.http
@@ -1,6 +1,10 @@
 ### Get all plants
 GET http://localhost:8080/api/v1/plants
-Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsdWthcy5rYXJzY2hAZ214LmRlIiwiaWF0IjoxNjk5ODczMDA4LCJleHAiOjE2OTk5NTk0MDh9.iU9gkWinFla3__ksuwLmKosevRXrrYlDdSQCPhNHxbM
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsdWthcy5rYXJzY2hAZ214LmRlIiwiaWF0IjoxNzAwOTMzNjQ4LCJleHAiOjE3MDEwMjAwNDh9.IXoMuNecB7ARvZpEyx5SraMbdoZrHgADeHd7wAo0ddw
+
+### Get garden entries
+GET http://localhost:8080/api/v1/garden
+Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsdWthcy5rYXJzY2hAZ214LmRlIiwiaWF0IjoxNzAwOTMzNjQ4LCJleHAiOjE3MDEwMjAwNDh9.IXoMuNecB7ARvZpEyx5SraMbdoZrHgADeHd7wAo0ddw
 
 ### Create account
 POST http://localhost:8080/api/v1/auth/register
@@ -19,5 +23,5 @@ content-type: application/json
 
 {
   "email": "lukas.karsch@gmx.de",
-  "password": "12345678"
+  "password": "myPassword123"
 }
diff --git a/src/main/java/hdm/mi/growbros/GrowBrosApplication.java b/src/main/java/hdm/mi/growbros/GrowBrosApplication.java
index 76f3ae045ba7566bddf05e09e7fda89cbdeee054..65b9ccdb6bc89e5710ba6366cdcdca4467ef0736 100644
--- a/src/main/java/hdm/mi/growbros/GrowBrosApplication.java
+++ b/src/main/java/hdm/mi/growbros/GrowBrosApplication.java
@@ -9,6 +9,9 @@ import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
+
+import java.util.List;
 
 
 @SpringBootApplication
@@ -20,17 +23,22 @@ public class GrowBrosApplication {
     }
 
     @Bean
+    @Profile("!test")
     public CommandLineRunner plants(PlantsService plantsService) {
         return (args) -> {
-            String jsonString = """
+            List<String> json = List.of("""
                     {"name":"Salat (Gartensalat)","latinName":"Lactuca sativa var. crispa","growingTips":"Salate eignen sich sehr gut als ‚Lückenfüller‘. Sie benötigen ausreichend Feuchtigkeit und haben einen vergleichsweise geringen Nährstoffbedarf. Durch eine geschickte Auswahl lassen sich Salate das ganze Jahr über anbauen: im Frühjahr und Frühsommer Kopf- und Schnitt-/Pflücksalate; im Sommer und Herbst Zichoriensalate und Eissalate sowie Feldsalat (v.a. im Herbst, Winter). Für eine kontinuierliche Ernte am besten in zeitlichen Abständen säen bzw. pflanzen. Arten und Sorten müssen dabei an die jeweilige Jahreszeit angepasst sein, z.B. beginnen Frühjahrssorten bei zu viel Hitze zu schießen. Dabei bildet sich ein langer Stiel und die Blätter werden bitter. Nach einigen Wochen kommen oben kleine Blüten zum Vorschein, woraus sich viele halbmondförmige Samen bilden. Diese können für das Folgejahr abgesammelt werden oder verteilen sich selbst im Beet, wenn du sie stehen lässt.\\n","description":"Salat steht als Überbegriff für viele Blattgemüse. Kopfsalate bilden - wie der Name schon sagt - einen Kopf und werden am Stück geerntet. Pflücksalate kann man kontinuierlich ernten, wenn man jeweils nur einzelne Blätter abpflückt. ","origin":"Gartensalate sind gezüchtete Lattichgewächse (Lactuca sativa) mit Urpsrung in Südeuropa, Nordafrika und Indien. Darunter fallen Kopfsalate (Batavia, Eissalat), Schnitt-/Pflücksalate (Lollo Rosso/Bionda, Eichblatt) und Römersalate.","plantWeekStart":12,"plantWeekEnd":35,"harvestWeekStart":15,"harvestWeekEnd":44,"growthDuration":6,"nutrientDemand":"MEDIUM","lightingDemand":"MEDIUM","waterDemand":"WET","groundType":null,"imageUrl":"https://d3t240q2dksnz7.cloudfront.net/a4cbb94a099179235fdd5696ae5f3833.jpg"}
-                    """;
+                    """, """
+                    {"name":"Kirschgroße gelbe Traube","latinName":"","description":"Ein Massenträger mit gigantischen Klumpentrauben von teils mehr als 100 Früchten.Nahezu kirschgroß, gelb, leicht oval und gut platzfest. Saftig würzig und süß schmeckend. Vermutlich Verbesserung einer Wildform.\\nÜber 2m hoch wachsend. Gleicht etwas 'Aurianticum' und 'Mirabell Gelb'. Relativ früh reifend.","origin":null,"plantWeekStart":20,"plantWeekEnd":22,"harvestWeekStart":26,"harvestWeekEnd":41,"growthDuration":12.5,"nutrientDemand":null,"lightingDemand":null,"waterDemand":null,"groundType":null,"imageUrl":"https://d3t240q2dksnz7.cloudfront.net/a214162d7e999d9fbb19ab75c69a0bdf.jpg"}
+                    """);
 
             ObjectMapper objectMapper = new ObjectMapper();
 
             try {
-                Plant plant = objectMapper.readValue(jsonString, Plant.class);
-                plantsService.createPlant(plant);
+                for (String s : json) {
+                    Plant plant = objectMapper.readValue(s, Plant.class);
+                    plantsService.createPlant(plant);
+                }
                 log.info("Saved mock plants");
             } catch (Exception e) {
                 log.error(e.getMessage());
diff --git a/src/main/java/hdm/mi/growbros/config/JpaConfiguration.java b/src/main/java/hdm/mi/growbros/config/JpaConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..54ca4b8665dc704fb1795445508bcfb305242fcd
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/config/JpaConfiguration.java
@@ -0,0 +1,9 @@
+package hdm.mi.growbros.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+@Configuration
+@EnableJpaAuditing
+public class JpaConfiguration {
+}
diff --git a/src/main/java/hdm/mi/growbros/controllers/GardenController.java b/src/main/java/hdm/mi/growbros/controllers/GardenController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b80425831061b2cf7a384c0fcc8c528aaea1e83
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/controllers/GardenController.java
@@ -0,0 +1,62 @@
+package hdm.mi.growbros.controllers;
+
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.models.user.User;
+import hdm.mi.growbros.service.GardenService;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/v1/garden")
+@RequiredArgsConstructor
+public class GardenController {
+    private static final Logger log = LoggerFactory.getLogger(GardenService.class);
+
+    private final GardenService gardenService;
+
+    @GetMapping
+    public ResponseEntity<List<Plant>> getPlantsInGarden(
+            @RequestParam(value = "sort", required = false) String sort,
+            @AuthenticationPrincipal User user
+    ) {
+        return ResponseEntity.ok(gardenService.getUserPlants(user, sort));
+    }
+
+    @GetMapping("/count")
+    public int getGardenSize(
+            @AuthenticationPrincipal User user
+    ) {
+        return gardenService.countByUser(user);
+    }
+
+    @PostMapping("/add/{plantId}")
+    public ResponseEntity<Plant> addPlantToGarden(
+            @PathVariable Long plantId,
+            @AuthenticationPrincipal User user
+    ) {
+        final Plant plantAdded = gardenService.addPlantToGarden(plantId, user);
+        return ResponseEntity.status(201).body(plantAdded);
+    }
+
+    @DeleteMapping("/remove/{entryId}")
+    public ResponseEntity<Void> removePlantFromGarden(
+            @PathVariable Long entryId,
+            @AuthenticationPrincipal User user
+    ) {
+        gardenService.removeFromGarden(entryId, user);
+        return ResponseEntity.status(204).build();
+    }
+
+    @DeleteMapping("/remove/all")
+    public int removeAllPlantsFromGarden(
+            @AuthenticationPrincipal User user
+    ) {
+        return gardenService.clearGarden(user);
+    }
+}
diff --git a/src/main/java/hdm/mi/growbros/exceptions/PlantNotFoundException.java b/src/main/java/hdm/mi/growbros/exceptions/PlantNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..e72d6b99e7c7a061ef2b88958d544033c5f3802c
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/exceptions/PlantNotFoundException.java
@@ -0,0 +1,7 @@
+package hdm.mi.growbros.exceptions;
+
+public class PlantNotFoundException extends RuntimeException {
+    public PlantNotFoundException(Long id) {
+        super(String.format("Plant with id '%d' was not found", id));
+    }
+}
diff --git a/src/main/java/hdm/mi/growbros/models/GardenEntry.java b/src/main/java/hdm/mi/growbros/models/GardenEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..58358dc42e11b4a43d8b9a065b2589a04d745428
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/models/GardenEntry.java
@@ -0,0 +1,48 @@
+package hdm.mi.growbros.models;
+
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.models.user.User;
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import java.util.Date;
+import java.util.Objects;
+
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class GardenEntry {
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @ManyToOne
+    private Plant plant;
+
+    @ManyToOne(optional = false)
+    private User user;
+
+    @CreatedDate
+    private Date createdAt;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        GardenEntry that = (GardenEntry) o;
+        return Objects.equals(id, that.id) && Objects.equals(plant, that.plant);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, plant);
+    }
+}
diff --git a/src/main/java/hdm/mi/growbros/models/plant/Plant.java b/src/main/java/hdm/mi/growbros/models/plant/Plant.java
index bf6cdefe539e92b8ef9efc7bc3e7ac100a6a4183..c4c4bcec7c4e1c261c13f88e1a8d17178e6ee20d 100644
--- a/src/main/java/hdm/mi/growbros/models/plant/Plant.java
+++ b/src/main/java/hdm/mi/growbros/models/plant/Plant.java
@@ -5,12 +5,14 @@ import jakarta.validation.constraints.Max;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotBlank;
 import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.hibernate.validator.constraints.URL;
 //careful! weeks are indexed at 0 -> max value is 51.
 
 @Data
+@Builder
 @AllArgsConstructor
 @NoArgsConstructor
 @Entity
diff --git a/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java b/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..54f20a1cdd9bc730b5c65103798f77d25ef5d7fa
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java
@@ -0,0 +1,52 @@
+package hdm.mi.growbros.repositories;
+
+import hdm.mi.growbros.models.GardenEntry;
+import hdm.mi.growbros.models.user.User;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface GardenRepository extends JpaRepository<GardenEntry, Long> {
+    List<GardenEntry> findByUser(User user);
+
+    List<GardenEntry> findByUser(User user, Sort sort);
+
+    int countByUser(User user);
+
+    int deleteAllByUser(User user);
+
+    void deleteByIdAndUser(Long entryId, User user);
+
+    @Query("""
+                SELECT ge FROM GardenEntry ge
+                WHERE ge.user = :user
+                ORDER BY
+                    CASE
+                        WHEN :week <= ge.plant.harvestWeekStart
+                            THEN ABS(:week - ge.plant.harvestWeekStart)
+                        ELSE ABS(52 + :week - ge.plant.harvestWeekStart)
+                    END,
+                    ge.plant.name
+                ASC
+            """)
+    List<GardenEntry> findAllByNearestHarvestWeek(@Param("user") User user, @Param("week") int currentWeek);
+
+    @Query("""
+                SELECT ge FROM GardenEntry ge
+                WHERE ge.user = :user
+                ORDER BY
+                    CASE
+                        WHEN :week <= ge.plant.plantWeekStart
+                            THEN ABS(:week - ge.plant.plantWeekStart)
+                        ELSE ABS(52 + :week - ge.plant.plantWeekStart)
+                    END,
+                    ge.plant.name
+                ASC
+            """)
+    List<GardenEntry> findAllByNearestPlantingWeek(@Param("user") User user, @Param("week") int currentWeek);
+}
diff --git a/src/main/java/hdm/mi/growbros/repositories/PlantRepository.java b/src/main/java/hdm/mi/growbros/repositories/PlantRepository.java
index c8c63d0d846571318cce64da6ec5043b21536dbc..b36a1b11d639b7cb3de39be717cfd9320f595b4e 100644
--- a/src/main/java/hdm/mi/growbros/repositories/PlantRepository.java
+++ b/src/main/java/hdm/mi/growbros/repositories/PlantRepository.java
@@ -4,6 +4,9 @@ import hdm.mi.growbros.models.plant.Plant;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 @Repository
 public interface PlantRepository extends JpaRepository<Plant, Long> {
+    List<Plant> findByNameIsLike(String name);
 }
diff --git a/src/main/java/hdm/mi/growbros/service/GardenService.java b/src/main/java/hdm/mi/growbros/service/GardenService.java
new file mode 100644
index 0000000000000000000000000000000000000000..e64aeacd20c2f7a885787789468a955e32499b26
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/service/GardenService.java
@@ -0,0 +1,85 @@
+package hdm.mi.growbros.service;
+
+import hdm.mi.growbros.exceptions.PlantNotFoundException;
+import hdm.mi.growbros.models.GardenEntry;
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.models.user.User;
+import hdm.mi.growbros.repositories.GardenRepository;
+import hdm.mi.growbros.repositories.PlantRepository;
+import hdm.mi.growbros.util.DateTimeUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class GardenService {
+    private final GardenRepository gardenRepository;
+    private final PlantRepository plantRepository;
+
+    public List<Plant> getUserPlants(User user, String sort) {
+        if (sort == null) return getAllPlantsOrderedByName(user);
+        return switch (sort) {
+            case "createdAt" -> getAllPlantsOrderedByCreatedDate(user);
+            case "plantDate" -> getAllPlantsOrderedByNextPossiblePlantDate(user);
+            case "harvestDate" -> getAllPlantsOrderedByNextPossibleHarvest(user);
+            default -> getAllPlantsOrderedByName(user);
+        };
+    }
+
+    public Plant addPlantToGarden(Long plantId, User user) {
+        //get user
+        Plant plant = plantRepository.findById(plantId).orElseThrow(() -> new PlantNotFoundException(plantId));
+        GardenEntry gardenEntry = new GardenEntry();
+        gardenEntry.setPlant(plant);
+        gardenEntry.setUser(user);
+        var result = gardenRepository.save(gardenEntry);
+        return result.getPlant();
+    }
+
+    public void removeFromGarden(Long entryId, User authenticatedUser) {
+        gardenRepository.deleteByIdAndUser(entryId, authenticatedUser);
+    }
+
+    public int clearGarden(User authenticatedUser) {
+        return gardenRepository.deleteAllByUser(authenticatedUser);
+    }
+
+    private List<Plant> getAllPlantsOrderedByName(User user) {
+        return mapGardenEntriesToPlants(
+                gardenRepository.findByUser(user, Sort.by("plant.name"))
+        );
+    }
+
+    private List<Plant> getAllPlantsOrderedByCreatedDate(User user) {
+        return mapGardenEntriesToPlants(
+                gardenRepository.findByUser(user, Sort.by("createdDate"))
+        );
+    }
+
+    private List<Plant> getAllPlantsOrderedByNextPossiblePlantDate(User user) {
+        return mapGardenEntriesToPlants(
+                gardenRepository.findAllByNearestPlantingWeek(user, DateTimeUtils.getCurrentWeekForToday())
+        );
+    }
+
+    private List<Plant> getAllPlantsOrderedByNextPossibleHarvest(User user) {
+        return mapGardenEntriesToPlants(
+                gardenRepository.findAllByNearestHarvestWeek(user, DateTimeUtils.getCurrentWeekForToday())
+        );
+    }
+
+    private List<Plant> mapGardenEntriesToPlants(Collection<GardenEntry> entries) {
+        return entries
+                .stream()
+                .map(GardenEntry::getPlant)
+                .toList();
+    }
+
+    public int countByUser(User user) {
+        return gardenRepository.countByUser(user);
+    }
+}
diff --git a/src/main/java/hdm/mi/growbros/service/PlantsService.java b/src/main/java/hdm/mi/growbros/service/PlantsService.java
index 4ba238dde706683df5514dc6e1a66a559f39d074..2d83c2c5538bd1437f96bcbc363f910a9f174671 100644
--- a/src/main/java/hdm/mi/growbros/service/PlantsService.java
+++ b/src/main/java/hdm/mi/growbros/service/PlantsService.java
@@ -47,4 +47,8 @@ public class PlantsService {
         log.info("Saving plant '{}' to repository.", plant.getName());
         plantRepository.save(plant);
     }
+
+    public List<Plant> search(String search) {
+        return plantRepository.findByNameIsLike(search);
+    }
 }
diff --git a/src/main/java/hdm/mi/growbros/util/DateTimeUtils.java b/src/main/java/hdm/mi/growbros/util/DateTimeUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..5faccd352f3e6f6536002f38fc9b3f223beabfdc
--- /dev/null
+++ b/src/main/java/hdm/mi/growbros/util/DateTimeUtils.java
@@ -0,0 +1,14 @@
+package hdm.mi.growbros.util;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+
+public class DateTimeUtils {
+    public static int getCurrentWeekForToday() {
+        return getCurrentWeekFromDate(LocalDate.now());
+    }
+
+    public static int getCurrentWeekFromDate(LocalDate date) {
+        return date.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
+    }
+}
diff --git a/src/test/java/hdm/mi/growbros/config/SpringSecurityTestConfig.java b/src/test/java/hdm/mi/growbros/config/SpringSecurityTestConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..24f4295782dd6275223969747ba07f98c9a05c15
--- /dev/null
+++ b/src/test/java/hdm/mi/growbros/config/SpringSecurityTestConfig.java
@@ -0,0 +1,61 @@
+package hdm.mi.growbros.config;
+
+import hdm.mi.growbros.models.user.User;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.provisioning.UserDetailsManager;
+
+import java.util.List;
+
+@TestConfiguration
+public class SpringSecurityTestConfig {
+    @Bean
+    @Primary
+    public UserDetailsService testUserDetailsService() {
+        User user1 = UserTestData.getUser1();
+        User user2 = UserTestData.getUser2();
+        User admin = UserTestData.getAdmin();
+
+        return new UserDetailsManager() {
+            private final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(List.of(user1, user2, admin));
+
+            @Override
+            public void createUser(UserDetails user) {
+                this.inMemoryUserDetailsManager.createUser(user);
+            }
+
+            @Override
+            public void updateUser(UserDetails user) {
+                this.inMemoryUserDetailsManager.updateUser(user);
+            }
+
+            @Override
+            public void deleteUser(String username) {
+                this.inMemoryUserDetailsManager.deleteUser(username);
+            }
+
+            @Override
+            public void changePassword(String s, String s1) {
+                this.inMemoryUserDetailsManager.changePassword(s, s1);
+            }
+
+            @Override
+            public boolean userExists(String s) {
+                return this.inMemoryUserDetailsManager.userExists(s);
+            }
+
+            @Override
+            public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+                if (s.equals("user1@gmail.com")) return user1;
+                if (s.equals("user2@gmail.com")) return user2;
+                if (s.equals("admin@gmail.com")) return admin;
+                throw new UsernameNotFoundException("Username " + s + " not found");
+            }
+        };
+    }
+}
diff --git a/src/test/java/hdm/mi/growbros/config/UserTestData.java b/src/test/java/hdm/mi/growbros/config/UserTestData.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc6a9fa3a3d3feff30896820bf74a05366663211
--- /dev/null
+++ b/src/test/java/hdm/mi/growbros/config/UserTestData.java
@@ -0,0 +1,29 @@
+package hdm.mi.growbros.config;
+
+import hdm.mi.growbros.models.user.Role;
+import hdm.mi.growbros.models.user.User;
+import lombok.Getter;
+
+public class UserTestData {
+    @Getter
+    private final static User user1 = User.builder()
+            .firstname("First user")
+            .email("user1@gmail.com")
+            .password("safePassword123!")
+            .role(Role.USER)
+            .build();
+    @Getter
+    private final static User user2 = User.builder()
+            .firstname("Second user")
+            .email("user2@gmail.com")
+            .password("safePassword123!")
+            .role(Role.USER)
+            .build();
+    @Getter
+    private final static User admin = User.builder()
+            .firstname("Admin user")
+            .email("admin@gmail.com")
+            .password("adminPassword123!")
+            .role(Role.ADMIN)
+            .build();
+}
diff --git a/src/test/java/hdm/mi/growbros/controllers/GardenControllerTest.java b/src/test/java/hdm/mi/growbros/controllers/GardenControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..47c579875a84f84e3144ce04d052cbb55ef0a60a
--- /dev/null
+++ b/src/test/java/hdm/mi/growbros/controllers/GardenControllerTest.java
@@ -0,0 +1,73 @@
+package hdm.mi.growbros.controllers;
+
+import hdm.mi.growbros.config.SpringSecurityTestConfig;
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.service.GardenService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+@SpringBootTest(classes = SpringSecurityTestConfig.class)
+@AutoConfigureMockMvc
+@ActiveProfiles("test")
+public class GardenControllerTest {
+    @Autowired
+    private MockMvc mvc;
+
+    @MockBean
+    private GardenService gardenService;
+
+    @Test
+    @WithMockUser
+    void gardenEntries_shouldBeOkJson_containList() throws Exception {
+        when(gardenService.getUserPlants(any(), any())).thenReturn(List.of(Plant.builder().name("Plant").build()));
+
+        mvc.perform(get("/api/v1/garden").contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+                .andExpect(jsonPath("$.size()").value(1))
+                .andDo(print());
+
+        verify(gardenService).getUserPlants(any(), any());
+    }
+
+    @Test
+    @WithMockUser
+    void creatingEntry_shouldBe201_andContainPlant() throws Exception {
+        //setup
+        when(gardenService.addPlantToGarden(anyLong(), any()))
+                .thenReturn(Plant.builder().name("My plant").build());
+
+        mvc.perform(post("/api/v1/garden/add/0").contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isCreated())
+                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+                .andExpect(jsonPath("$.name").value("My plant"))
+                .andDo(print());
+
+        verify(gardenService).addPlantToGarden(anyLong(), any());
+    }
+
+    @Test
+    @WithMockUser
+    void deletingEntry_shouldBe204() throws Exception {
+        mvc.perform(delete("/api/v1/garden/remove/1").contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isNoContent())
+                .andDo(print());
+    }
+}
diff --git a/src/test/java/hdm/mi/growbros/repositories/GardenRepositoryTest.java b/src/test/java/hdm/mi/growbros/repositories/GardenRepositoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6aa97c9ff6e3a85017ae3880d45f037e5bd7a8ae
--- /dev/null
+++ b/src/test/java/hdm/mi/growbros/repositories/GardenRepositoryTest.java
@@ -0,0 +1,119 @@
+package hdm.mi.growbros.repositories;
+
+import hdm.mi.growbros.models.GardenEntry;
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.models.user.Role;
+import hdm.mi.growbros.models.user.User;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+//TODO: Test for when the current week is in between plant/harvest start and end date
+
+@DataJpaTest
+@ActiveProfiles("test")
+class GardenRepositoryTest {
+    @Autowired
+    private GardenRepository underTest;
+
+    @Autowired
+    private TestEntityManager entityManager;
+
+    private GardenEntry ge1, ge2, ge3, ge4;
+    private User user1, user2;
+
+    @BeforeEach
+    public void setupEach() {
+        user1 = User.builder()
+                .email("user1@gmail.com")
+                .role(Role.USER)
+                .password("safePassword123!")
+                .build();
+        entityManager.persist(user1);
+
+        user2 = User.builder()
+                .email("user2@gmail.com")
+                .role(Role.USER)
+                .password("safePassword123!")
+                .build();
+        entityManager.persist(user2);
+
+        Plant p1 = Plant.builder()
+                .name("Early plant")
+                .plantWeekStart(1)
+                .plantWeekEnd(3)
+                .harvestWeekStart(10)
+                .harvestWeekEnd(15)
+                .build();
+        entityManager.persist(p1);
+        Plant p2 = Plant.builder()
+                .name("Medium late plant")
+                .plantWeekStart(4)
+                .plantWeekEnd(6)
+                .harvestWeekStart(18)
+                .harvestWeekEnd(20)
+                .build();
+        entityManager.persist(p2);
+        Plant p3 = Plant.builder()
+                .name("Late plant")
+                .plantWeekStart(10)
+                .plantWeekEnd(15)
+                .harvestWeekStart(25)
+                .harvestWeekEnd(30)
+                .build();
+        entityManager.persist(p3);
+        ge1 = new GardenEntry(0L, p1, user1, null);
+        ge2 = new GardenEntry(0L, p2, user1, null);
+        ge3 = new GardenEntry(0L, p3, user1, null);
+        ge4 = new GardenEntry(0L, p3, user2, null);
+        underTest.saveAll(List.of(ge1, ge2, ge3, ge4));
+    }
+
+    @Test
+    void shouldReturnCorrectList_ofEntriesForUser_orderedByNearestHarvestWeek() {
+        //when
+        var result = underTest.findAllByNearestHarvestWeek(user1, 1);
+
+        //expect
+        assertEquals(List.of(ge1, ge2, ge3), result);
+    }
+
+    @Test
+    void shouldReturnCorrectList_ofEntriesForUser_orderedByNearestPlantingWeek() {
+        //when
+        var result = underTest.findAllByNearestPlantingWeek(user1, 1);
+
+        //expect
+        assertEquals(List.of(ge1, ge2, ge3), result);
+    }
+
+    @Test
+    void shouldDeleteCorrectEntries_whenClearingGarden_forUser() {
+        //when
+        int deleted = underTest.deleteAllByUser(user2);
+
+        //expect
+        assertEquals(1, deleted);
+        assertEquals(List.of(), underTest.findByUser(user2));
+        assertThat(List.of(ge1, ge2, ge3)).hasSameElementsAs(underTest.findByUser(user1));
+    }
+
+    @Test
+    void countShouldBeCorrect_forUser() {
+        //when
+        int user1Count = underTest.countByUser(user1);
+        int user2Count = underTest.countByUser(user2);
+
+        //expect
+        assertEquals(3, user1Count);
+        assertEquals(1, user2Count);
+    }
+}
diff --git a/src/test/java/hdm/mi/growbros/service/GardenServiceTest.java b/src/test/java/hdm/mi/growbros/service/GardenServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b672464d13dfd5083c5f9ad318c46f44f17a476d
--- /dev/null
+++ b/src/test/java/hdm/mi/growbros/service/GardenServiceTest.java
@@ -0,0 +1,90 @@
+package hdm.mi.growbros.service;
+
+import hdm.mi.growbros.config.UserTestData;
+import hdm.mi.growbros.exceptions.PlantNotFoundException;
+import hdm.mi.growbros.models.GardenEntry;
+import hdm.mi.growbros.models.plant.Plant;
+import hdm.mi.growbros.models.user.User;
+import hdm.mi.growbros.repositories.GardenRepository;
+import hdm.mi.growbros.repositories.PlantRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.data.domain.Sort;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+@ActiveProfiles("test")
+class GardenServiceTest {
+    @MockBean
+    private GardenRepository gardenRepository;
+    @MockBean
+    private PlantRepository plantRepository;
+
+    @Autowired
+    private GardenService gardenService;
+
+    @Test
+    void shouldThrow_whenAddingPlant_thatDoesNotExist() {
+        //setup
+        when(plantRepository.findById(100L)).thenReturn(Optional.empty());
+
+        assertThrows(PlantNotFoundException.class, () -> gardenService.addPlantToGarden(100L, UserTestData.getUser1()));
+    }
+
+    @Test
+    void shouldReturn_whenAddingExistingPlant() {
+        //setup
+        Plant plant = Plant.builder().name("Plant!").build();
+        when(plantRepository.findById(1L)).thenReturn(Optional.of(plant));
+        when(gardenRepository.save(
+                any(GardenEntry.class))
+        ).thenReturn(new GardenEntry(0L, plant, null, null));
+
+        //assert
+        var result = gardenService.addPlantToGarden(1L, UserTestData.getUser1());
+        assertEquals(result, plant);
+    }
+
+    @Test
+    void shouldReturnEntries_inCorrectOrder() {
+        //setup
+        Plant p1 = Plant.builder().name("AAA").build();
+        Plant p2 = Plant.builder().name("BBB").build();
+        Plant p3 = Plant.builder().name("CCC").build();
+        var orderedByNameMock = List.of(p1, p2, p3);
+        var orderedByCreatedMock = List.of(p2, p1, p3);
+        var orderedByHarvestMock = List.of(p1, p3, p2);
+        var orderedByPlantDateMock = List.of(p3, p2, p1);
+
+        User user = UserTestData.getUser1();
+
+        when(gardenRepository.findByUser(user, Sort.by("createdDate"))).thenReturn(mapPlantsToGardenEntries(orderedByCreatedMock, user));
+        when(gardenRepository.findByUser(user, Sort.by("plant.name"))).thenReturn(mapPlantsToGardenEntries(orderedByNameMock, user));
+        when(gardenRepository.findAllByNearestHarvestWeek(eq(user), any(int.class))).thenReturn(mapPlantsToGardenEntries(orderedByHarvestMock, user));
+        when(gardenRepository.findAllByNearestPlantingWeek(eq(user), any(int.class))).thenReturn(mapPlantsToGardenEntries(orderedByPlantDateMock, user));
+
+        assertAll(
+                () -> assertEquals(gardenService.getUserPlants(user, null), orderedByNameMock),
+                () -> assertEquals(gardenService.getUserPlants(user, "random stuff"), orderedByNameMock),
+                () -> assertEquals(gardenService.getUserPlants(user, "createdAt"), orderedByCreatedMock),
+                () -> assertEquals(gardenService.getUserPlants(user, "plantDate"), orderedByPlantDateMock),
+                () -> assertEquals(gardenService.getUserPlants(user, "harvestDate"), orderedByHarvestMock)
+        );
+    }
+
+    private List<GardenEntry> mapPlantsToGardenEntries(List<Plant> plants, User user) {
+        return plants.stream()
+                .map(plant -> new GardenEntry(0L, plant, user, null))
+                .toList();
+    }
+}
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
new file mode 100644
index 0000000000000000000000000000000000000000..78a391386deb0e15b64d67032fd14078b186f356
--- /dev/null
+++ b/src/test/resources/application.properties
@@ -0,0 +1,8 @@
+spring.datasource.url=jdbc:h2:mem:testdb
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=admin
+spring.datasource.password=admin
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
+spring.h2.console.enabled=true
+spring.profiles.active=test
\ No newline at end of file