Task A: Spring Initializr

This task involves creating the project with the initial set of four dependencies and setting up the application properties.

Step-by-step instructions:

  1. You have already created the project. The pom.xml you provided is a correct starting point, as it includes only the four required dependencies.
  2. Navigate to src/main/resources/.
  3. Open or create the application.properties file.
  4. Paste the contents you provided from the lab environment into this file.

File: src/main/resources/application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/full-stack-ecommerce?useSSL=false&useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=UTC
spring.datasource.username=ecommerceapp
spring.datasource.password=ecommerceapp
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
 
spring.jpa.hibernate.ddl-auto=none
 
spring.data.rest.base-path=/api
 
# allow jackson parser to process comments in payload
spring.jackson.parser.allow-comments=true
# application logging level
logging.level.org.springframework=INFO

Knowledge Transfer: The application.properties file is the central place for Spring Boot configuration. We are telling Spring how to connect to our MySQL database, what SQL dialect to use, and setting the base path for our REST API to /api. The setting spring.jpa.hibernate.ddl-auto=none is critical; it tells Hibernate (our JPA implementation) not to modify the database schema, as we are using a pre-existing one.

Task B: Git Repository

This is an ongoing task. You will commit your changes after completing each major step.

Step-by-step instructions for each commit:

  1. In your project’s root directory, add your changes to the staging area:
    git add .
  2. Commit the changes with a message reflecting the completed task:
    git commit -m "C: Constructed package structure and added config"
  3. Push your commit to GitLab:
    git push

At the very end of the project, you will retrieve the repository URL and the branch history (git log --oneline) for submission.

Task C: Package Construction

Here, we will create the required package structure and configure the REST endpoints by adding the provided RestDataConfig class.

Step-by-step instructions:

  1. In your IDE, under your main package (e.g., src/main/java/edu/wgu/d288_backend), create these four packages:
    • controllers
    • dao
    • entities
    • services
  2. Create one more package:
    • config
  3. Inside the config package, create a new Java class named RestDataConfig.java.
  4. Paste the provided code into this file. You must update the package and import statements to match your project’s package structure.

File: src/main/java/edu/wgu/d288_backend/config/RestDataConfig.java

package edu.wgu.d288_backend.config; // <-- Your package name
 
import edu.wgu.d288_backend.entities.*; // <-- Your package name
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
 
@Configuration
public class RestDataConfig implements RepositoryRestConfigurer {
 
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
        config.exposeIdsFor(Country.class);
        config.exposeIdsFor(Customer.class);
        config.exposeIdsFor(Division.class);
        config.exposeIdsFor(Excursion.class);
        config.exposeIdsFor(Vacation.class);
        config.setDefaultPageSize(Integer.MAX_VALUE);
        config.setMaxPageSize(Integer.MAX_VALUE);
    }
}

Knowledge Transfer: Spring Data REST automatically creates REST endpoints for your repositories. This configuration class customizes that behavior. Specifically, config.exposeIdsFor(...) tells Spring to include the entity’s primary key id field in the JSON response, which the front-end often needs.

Now, commit your work: git commit -m "C: Constructed package structure and added config"

Task D: Entities Package

We will create the Java classes (Entities) that map to the database tables shown in the ERD. We’ll use Lombok annotations to reduce boilerplate code like getters and setters.

Knowledge Transfer: An “Entity” is a special Java class that the Java Persistence API (JPA) can map to a database table. Annotations like @Entity, @Table, @Id, @Column, and relationship annotations (@ManyToOne, @OneToMany, etc.) are used to define this mapping. @CreationTimestamp and @UpdateTimestamp are convenient Hibernate annotations that automatically manage the create_date and last_update fields.

Create the following files inside the src/main/java/edu/wgu/d288_backend/entities/ package.

File: entities/StatusType.java

package edu.wgu.d288_backend.entities;
 
public enum StatusType {
    pending,
    ordered,
    cancelled
}

File: entities/Country.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.util.Date;
import java.util.Set;
 
@Entity
@Table(name="countries")
@Data
public class Country {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="country_id")
    private Long id;
 
    @Column(name="country")
    private String country_name;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "country")
    private Set<Division> divisions;
}

File: entities/Division.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.util.Date;
import java.util.Set;
 
@Entity
@Table(name="divisions")
@Data
public class Division {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="division_id")
    private Long id;
 
    @Column(name="division")
    private String division_name;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @ManyToOne
    @JoinColumn(name="country_id")
    private Country country;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "division")
    private Set<Customer> customers;
}

File: entities/Customer.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.util.Date;
import java.util.Set;
import java.util.HashSet;
 
@Entity
@Table(name="customers")
@Getter
@Setter
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="customer_id")
    private Long id;
 
    @Column(name="customer_first_name")
    private String firstName;
 
    @Column(name="customer_last_name")
    private String lastName;
 
    @Column(name="address")
    private String address;
 
    @Column(name="postal_code")
    private String postal_code;
 
    @Column(name="phone")
    private String phone;
    
    @Column(name="city")
    private String city;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @ManyToOne
    @JoinColumn(name = "division_id")
    private Division division;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
    private Set<Cart> carts = new HashSet<>();
    
    public Customer() {}
 
    public Customer(String firstName, String lastName, String address, String postal_code, String phone, String city, Division division) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
        this.postal_code = postal_code;
        this.phone = phone;
        this.city = city;
        this.division = division;
    }
 
    public void addCart(Cart cart) {
        if (cart != null) {
            carts.add(cart);
            cart.setCustomer(this);
        }
    }
}

File: entities/Vacation.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;
 
@Entity
@Table(name="vacations")
@Data
public class Vacation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="vacation_id")
    private Long id;
 
    @Column(name="vacation_title")
    private String vacation_title;
 
    @Column(name="description")
    private String description;
 
    @Column(name="travel_fare_price")
    private BigDecimal travel_fare_price;
 
    @Column(name="image_url")
    private String image_URL;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "vacation")
    private Set<Excursion> excursions;
}

File: entities/Excursion.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;
 
@Entity
@Table(name="excursions")
@Data
public class Excursion {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="excursion_id")
    private Long id;
 
    @Column(name="excursion_title")
    private String excursion_title;
 
    @Column(name="excursion_price")
    private BigDecimal excursion_price;
 
    @Column(name="image_url")
    private String image_URL;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @ManyToOne
    @JoinColumn(name="vacation_id", nullable=false)
    private Vacation vacation;
 
    @ManyToMany(mappedBy = "excursions")
    private Set<CartItem> cartItems;
}

File: entities/Cart.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;
import java.util.HashSet;
 
@Entity
@Table(name="carts")
@Getter
@Setter
public class Cart {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cart_id")
    private Long id;
 
    @Column(name="package_price")
    private BigDecimal package_price;
 
    @Column(name="party_size")
    private int party_size;
 
    @Enumerated(EnumType.STRING)
    @Column(name="status")
    private StatusType status;
 
    @Column(name="order_tracking_number")
    private String orderTrackingNumber;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @ManyToOne
    @JoinColumn(name="customer_id")
    private Customer customer;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "cart")
    private Set<CartItem> cartItems = new HashSet<>();
 
    public void add(CartItem item) {
        if (item != null) {
            cartItems.add(item);
            item.setCart(this);
        }
    }
}

File: entities/CartItem.java

package edu.wgu.d288_backend.entities;
 
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.util.Date;
import java.util.Set;
import java.util.HashSet;
 
@Entity
@Table(name="cart_items")
@Getter
@Setter
public class CartItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cart_item_id")
    private Long id;
 
    @Column(name="create_date")
    @CreationTimestamp
    private Date create_date;
 
    @Column(name="last_update")
    @UpdateTimestamp
    private Date last_update;
 
    @ManyToOne
    @JoinColumn(name="vacation_id")
    private Vacation vacation;
 
    @ManyToOne
    @JoinColumn(name = "cart_id")
    private Cart cart;
 
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="excursion_cartitem",
            joinColumns=@JoinColumn(name="cart_item_id"),
            inverseJoinColumns=@JoinColumn(name="excursion_id"))
    private Set<Excursion> excursions = new HashSet<>();
}

Now, commit your changes: git commit -m "D: Created entity classes"

Task E: DAO (Repositories) Package

A repository provides an abstraction for data access. We define an interface that extends JpaRepository, and Spring Data JPA automatically provides the implementation for standard CRUD operations.

Knowledge Transfer:

  • JpaRepository<EntityType, PrimaryKeyType>: Extending this interface gives us methods like save(), findById(), findAll(), etc., for free.
  • @CrossOrigin("http://localhost:4200"): This annotation enables Cross-Origin Resource Sharing. It tells the browser that it is safe to allow requests from the Angular front-end (running on localhost:4200) to access this API endpoint. This is a security feature built into browsers.

Create the following interfaces inside the src/main/java/edu/wgu/d288_backend/dao/ package.

File: dao/CountryRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Country;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface CountryRepository extends JpaRepository<Country, Long> {
}

File: dao/CustomerRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}

File: dao/DivisionRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Division;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface DivisionRepository extends JpaRepository<Division, Long> {
}

File: dao/ExcursionRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Excursion;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface ExcursionRepository extends JpaRepository<Excursion, Long> {
}

File: dao/VacationRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Vacation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface VacationRepository extends JpaRepository<Vacation, Long> {
}

File: dao/CartRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.Cart;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface CartRepository extends JpaRepository<Cart, Long> {
}

File: dao/CartItemRepository.java

package edu.wgu.d288_backend.dao;
 
import edu.wgu.d288_backend.entities.CartItem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
 
@CrossOrigin("http://localhost:4200")
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
}

Now, commit your changes: git commit -m "E: Created repository interfaces"

Task F: Services Package

The service layer contains the application’s business logic. We will create the CheckoutService to handle the process of placing an order. This involves creating Data Transfer Objects (DTOs) for the purchase data and response.

Knowledge Transfer:

  • DTO (Data Transfer Object): Purchase and PurchaseResponse are DTOs. They are simple classes used to carry data between the controller and the service, but they are not mapped to the database themselves.
  • Service Layer (@Service): This is where business logic lives. It coordinates calls to different repositories to perform a complete operation, like placing an order.
  • @Transactional: A crucial annotation that wraps a method in a database transaction. If any part of the placeOrder method fails (e.g., an SQL error), all the database changes made within that method are automatically rolled back. This ensures data consistency.

Create the following files in the src/main/java/edu/wgu/d288_backend/services/ package.

File: services/Purchase.java

package edu.wgu.d288_backend.services;
 
import edu.wgu.d288_backend.entities.Cart;
import edu.wgu.d288_backend.entities.CartItem;
import edu.wgu.d288_backend.entities.Customer;
import lombok.Data;
import java.util.Set;
 
@Data
public class Purchase {
    private Customer customer;
    private Cart cart;
    private Set<CartItem> cartItems;
}

File: services/PurchaseResponse.java

package edu.wgu.d288_backend.services;
 
import lombok.Data;
import lombok.NonNull;
 
@Data
public class PurchaseResponse {
    @NonNull
    private String orderTrackingNumber;
}

File: services/CheckoutService.java

package edu.wgu.d288_backend.services;
 
public interface CheckoutService {
    PurchaseResponse placeOrder(Purchase purchase);
}

File: services/CheckoutServiceImpl.java

package edu.wgu.d288_backend.services;
 
import edu.wgu.d288_backend.dao.CustomerRepository;
import edu.wgu.d288_backend.entities.Cart;
import edu.wgu.d288_backend.entities.CartItem;
import edu.wgu.d288_backend.entities.Customer;
import edu.wgu.d288_backend.entities.StatusType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.Set;
import java.util.UUID;
 
@Service
public class CheckoutServiceImpl implements CheckoutService {
 
    private final CustomerRepository customerRepository;
 
    @Autowired
    public CheckoutServiceImpl(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }
 
    @Override
    @Transactional
    public PurchaseResponse placeOrder(Purchase purchase) {
        Cart cart = purchase.getCart();
 
        String orderTrackingNumber = generateOrderTrackingNumber();
        cart.setOrderTrackingNumber(orderTrackingNumber);
        cart.setStatus(StatusType.ordered);
 
        Set<CartItem> cartItems = purchase.getCartItems();
        cartItems.forEach(cart::add);
 
        Customer customer = purchase.getCustomer();
        customer.addCart(cart);
 
        customerRepository.save(customer);
 
        return new PurchaseResponse(orderTrackingNumber);
    }
 
    private String generateOrderTrackingNumber() {
        return UUID.randomUUID().toString();
    }
}

Now, commit your changes: git commit -m "F: Created service layer for checkout"

Task G: Validation

To enforce the inputs required by the front-end, we will add validation. This requires a new dependency.

Step-by-step instructions:

  1. Add the validation dependency: Open your pom.xml file. Add the following dependency inside the <dependencies> section.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
  2. Reload Maven: After adding the dependency, your IDE will prompt you to “Load Maven Changes” or “Import Changes”. Do this to download the necessary library.

  3. Add validation annotations: Now, modify the Purchase.java DTO to include @NotNull annotations.

File: services/Purchase.java (Updated)

package edu.wgu.d288_backend.services;
 
import edu.wgu.d288_backend.entities.Cart;
import edu.wgu.d288_backend.entities.CartItem;
import edu.wgu.d288_backend.entities.Customer;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.Set;
 
@Data
public class Purchase {
    @NotNull
    private Customer customer;
    @NotNull
    private Cart cart;
    @NotNull
    private Set<CartItem> cartItems;
}

Knowledge Transfer: The spring-boot-starter-validation dependency adds Hibernate Validator to our project. This allows us to use standard validation annotations (from jakarta.validation.constraints). @NotNull ensures that the annotated field must not be null. In the next step, we will use @Valid in our controller to tell Spring to enforce these rules on incoming requests. If validation fails, Spring automatically sends a 400 Bad Request response, protecting our business logic from incomplete data.

Now, commit your changes: git commit -m "G: Added validation dependency and annotations"

Task H: Controllers Package

The controller creates the public-facing API endpoint. It receives HTTP requests and delegates the work to the service layer.

Knowledge Transfer:

  • @RestController: Marks this class as a request handler and ensures the return values are automatically converted to JSON and written to the HTTP response.
  • @RequestMapping("/api/checkout"): Maps all requests under this path to this controller.
  • @PostMapping("/purchase"): Maps specifically HTTP POST requests for /api/checkout/purchase to the placeOrder method.
  • @RequestBody: Deserializes the JSON from the request body into a Purchase object.
  • @Valid: This annotation, placed next to @RequestBody, is what triggers the validation we set up in Task G.

Create the following file in the src/main/java/edu/wgu/d288_backend/controllers/ package.

File: controllers/CheckoutController.java

package edu.wgu.d288_backend.controllers;
 
import edu.wgu.d288_backend.services.CheckoutService;
import edu.wgu.d288_backend.services.Purchase;
import edu.wgu.d288_backend.services.PurchaseResponse;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
 
@CrossOrigin("http://localhost:4200")
@RestController
@RequestMapping("/api/checkout")
public class CheckoutController {
 
    private final CheckoutService checkoutService;
 
    public CheckoutController(CheckoutService checkoutService) {
        this.checkoutService = checkoutService;
    }
 
    @PostMapping("/purchase")
    public PurchaseResponse placeOrder(@Valid @RequestBody Purchase purchase) {
        return checkoutService.placeOrder(purchase);
    }
}

Now, commit your changes: git commit -m "H: Created Checkout REST Controller"

Task I: Add Sample Customers

We’ll create a component to “bootstrap” our database with initial data. This will run once when the application starts up.

Knowledge Transfer:

  • CommandLineRunner: An interface that defines a run method. Spring Boot executes this method automatically after the application context is loaded. It’s a common pattern for running initialization code.
  • @Component: This marks the class as a Spring bean, so Spring will manage its lifecycle and execute the CommandLineRunner interface.
  • We check if customerRepository.count() == 0 to satisfy the requirement that data is not overwritten on every application start. The code will only run if the customers table is empty.

Step-by-step instructions:

  1. Create a new package named bootstrap.
  2. Inside the src/main/java/edu/wgu/d288_backend/bootstrap/ package, create the following class.

File: bootstrap/BootstrapData.java

package edu.wgu.d288_backend.bootstrap;
 
import edu.wgu.d288_backend.dao.CustomerRepository;
import edu.wgu.d288_backend.dao.DivisionRepository;
import edu.wgu.d288_backend.entities.Customer;
import edu.wgu.d288_backend.entities.Division;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
 
@Component
public class BootstrapData implements CommandLineRunner {
 
    private final CustomerRepository customerRepository;
    private final DivisionRepository divisionRepository;
 
    public BootstrapData(CustomerRepository customerRepository, DivisionRepository divisionRepository) {
        this.customerRepository = customerRepository;
        this.divisionRepository = divisionRepository;
    }
 
    @Override
    public void run(String... args) throws Exception {
 
        if (customerRepository.count() == 0) {
            Division division1 = divisionRepository.findById(2L).orElse(null);
            Division division2 = divisionRepository.findById(3L).orElse(null);
            Division division3 = divisionRepository.findById(4L).orElse(null);
 
            Customer customer1 = new Customer("John", "Doe", "123 Main St", "12345", "555-1111", "Anytown", division1);
            Customer customer2 = new Customer("Jane", "Smith", "456 Oak Ave", "67890", "555-2222", "Somecity", division2);
            Customer customer3 = new Customer("Peter", "Jones", "789 Pine Ln", "13579", "555-3333", "Anotherplace", division3);
            Customer customer4 = new Customer("Mary", "Williams", "321 Elm Rd", "24680", "555-4444", "Metropolis", division1);
            Customer customer5 = new Customer("David", "Brown", "654 Birch Ct", "97531", "555-5555", "Villageton", division2);
 
            customerRepository.save(customer1);
            customerRepository.save(customer2);
            customerRepository.save(customer3);
            customerRepository.save(customer4);
            customerRepository.save(customer5);
        }
    }
}

Now, commit your changes: git commit -m "I: Added bootstrap to add 5 sample customers"

Task J: Run Application and Provide Screenshots

This is the final step where you test the full integration.

Step-by-step instructions:

  1. Run your Spring Boot application from your IDE.
  2. Run the provided Angular front-end application (e.g., with ng serve).
  3. Open http://localhost:4200 in your browser.
  4. Open the Developer Tools (F12) and go to the “Network” tab.
  5. Use the application to select a vacation, add two excursions, and complete the checkout form.
  6. Click “Purchase”.
  7. Take the first screenshot: Show the browser window. It should include the front-end UI and the Network tab of the developer tools, showing a purchase request with a 200 OK status, proving there was no network error.
  8. Open MySQL Workbench and connect to the full-stack-ecommerce database.
  9. Run queries to verify the data was saved.
    -- Find the most recent cart that was fully ordered
    SELECT * FROM carts WHERE order_tracking_number IS NOT NULL ORDER BY last_update DESC LIMIT 1;
     
    -- Using the cart_id from the above query, find its items
    SELECT * FROM cart_items WHERE cart_id = [ID_FROM_PREVIOUS_QUERY];
     
    -- Using a cart_item_id from the above query, find its excursions
    SELECT * FROM excursion_cartitem WHERE cart_item_id = [ID_FROM_PREVIOUS_QUERY];
  10. Take the second screenshot: Show the MySQL Workbench window with the results of these queries, confirming that the cart, cart items, and the links to their excursions were successfully persisted.

You have now completed all technical requirements for the project. The final step is to collect your GitLab URL and commit history for submission.