Order tracking endpoint for the tracking page

Java · Spring Boot · beginner · modification

Adds the backend for the new order tracking page. `OrderTrackingController` serves `GET /api/orders/{orderId}/tracking`: it loads the order through the existing `findByIdAndCustomerId` (so another customer's order is a plain 404), looks up the order's shipment with a new `ShipmentRepository.findByOrderId`, and returns a `TrackingView` record. `TrackingView.of` copies the order's id and status and, when there is a shipment, the shipment details the page needs; before shipping those stay `null`.

Shop backend on Spring Boot 3.3 (Java 21), Spring Data JPA (Hibernate 6) on PostgreSQL, Spring Security. Every `/api/**` request needs a signed-in session; the principal is a `ShopUser(Long customerId, String email)` record that `@AuthenticationPrincipal` resolves, and `customerId` is never null. Existing and unchanged: the `Order` entity (`id`, `customerId`, `status` stored as an `OrderStatus` enum name: `PLACED`, `PACKED`, `SHIPPED`, `DELIVERED`, `CANCELLED`), `OrderRepository` with `Optional<Order> findByIdAndCustomerId(Long id, Long customerId)`, and the `Shipment` entity (`id`, `orderId`, `carrier`, `trackingNumber`, `estimatedDelivery` as a `LocalDate`). The warehouse creates the shipment row when it buys the label, with all three of `carrier`, `trackingNumber` and `estimatedDelivery` set, and `shipments.order_id` is unique, so an order has at most one shipment. Jackson runs with Spring Boot's defaults, which write a `LocalDate` as `"yyyy-MM-dd"`. A non-numeric `{orderId}` is answered with 400 by Spring MVC before the method runs. The tracking page itself is a separate frontend change.

Requirements

Files touched

--- src/main/java/com/acme/shop/orders/ShipmentRepository.java
 package com.acme.shop.orders;
 
+import java.util.Optional;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface ShipmentRepository extends JpaRepository<Shipment, Long> {
+
+    Optional<Shipment> findByOrderId(Long orderId);
 }
 
--- src/main/java/com/acme/shop/orders/TrackingView.java
+package com.acme.shop.orders;
+
+public record TrackingView(
+        Long orderId,
+        OrderStatus status,
+        String carrier,
+        String trackingNumber) {
+
+    public static TrackingView of(Order order, Shipment shipment) {
+        if (shipment == null) {
+            return new TrackingView(order.getId(), order.getStatus(), null, null);
+        }
+        return new TrackingView(
+                order.getId(),
+                order.getStatus(),
+                shipment.getCarrier(),
+                shipment.getTrackingNumber());
+    }

Review this PR

Java practice