From 20eb353aadb98d4af9f7556d6c02712d31e9869f Mon Sep 17 00:00:00 2001 From: josh-uk Date: Mon, 29 Dec 2025 16:22:02 +0000 Subject: [PATCH] poc --- .../uk/gov/hmcts/dts/fact/Application.java | 3 +- .../clients/AzureMapsRouteMatrixClient.java | 28 ++++ .../config/AzureMapsFeignConfiguration.java | 24 +++ .../fact/controllers/SearchController.java | 10 ++ .../dts/fact/entity/CourtByRoadDistance.java | 16 ++ .../fact/entity/CourtRoadDistanceCache.java | 24 +++ .../uk/gov/hmcts/dts/fact/model/Feature.java | 20 +++ .../uk/gov/hmcts/dts/fact/model/Geometry.java | 18 +++ .../gov/hmcts/dts/fact/model/MatrixCell.java | 17 ++ .../gov/hmcts/dts/fact/model/Properties.java | 13 ++ .../dts/fact/model/RouteMatrixRequest.java | 19 +++ .../dts/fact/model/RouteMatrixResponse.java | 12 ++ .../uk/gov/hmcts/dts/fact/model/Summary.java | 11 ++ .../CourtRoadDistanceCacheRepository.java | 7 + .../CourtWithDistanceRepository.java | 9 ++ .../dts/fact/services/AzureMapsService.java | 150 ++++++++++++++++++ .../hmcts/dts/fact/services/CourtService.java | 9 +- src/main/resources/application.yaml | 6 + .../V215__cache_postcode_results.sql | 5 + 19 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/clients/AzureMapsRouteMatrixClient.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/config/AzureMapsFeignConfiguration.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/entity/CourtByRoadDistance.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/entity/CourtRoadDistanceCache.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/Feature.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/Geometry.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/MatrixCell.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/Properties.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixRequest.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixResponse.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/model/Summary.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtRoadDistanceCacheRepository.java create mode 100644 src/main/java/uk/gov/hmcts/dts/fact/services/AzureMapsService.java create mode 100644 src/main/resources/db/migration/V215__cache_postcode_results.sql diff --git a/src/main/java/uk/gov/hmcts/dts/fact/Application.java b/src/main/java/uk/gov/hmcts/dts/fact/Application.java index 391f45116..5c2c02ad5 100644 --- a/src/main/java/uk/gov/hmcts/dts/fact/Application.java +++ b/src/main/java/uk/gov/hmcts/dts/fact/Application.java @@ -5,10 +5,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import uk.gov.hmcts.dts.fact.mapit.MapitClient; @SpringBootApplication -@EnableFeignClients(basePackageClasses = MapitClient.class) +@EnableFeignClients @ImportAutoConfiguration({FeignAutoConfiguration.class}) @SuppressWarnings("HideUtilityClassConstructor") // Spring needs a constructor, its not a utility class public class Application { diff --git a/src/main/java/uk/gov/hmcts/dts/fact/clients/AzureMapsRouteMatrixClient.java b/src/main/java/uk/gov/hmcts/dts/fact/clients/AzureMapsRouteMatrixClient.java new file mode 100644 index 000000000..9a30803a3 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/clients/AzureMapsRouteMatrixClient.java @@ -0,0 +1,28 @@ +package uk.gov.hmcts.dts.fact.clients; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import uk.gov.hmcts.dts.fact.config.AzureMapsFeignConfiguration; +import uk.gov.hmcts.dts.fact.model.RouteMatrixRequest; +import uk.gov.hmcts.dts.fact.model.RouteMatrixResponse; + +@FeignClient( + name = "azureMapsRouteMatrixClient", + url = "https://atlas.microsoft.com", + configuration = AzureMapsFeignConfiguration.class +) +public interface AzureMapsRouteMatrixClient { + + @PostMapping( + value = "/route/matrix", + consumes = MediaType.APPLICATION_JSON_VALUE + ) + RouteMatrixResponse calculateMatrix( + @RequestParam("api-version") String apiVersion, + @RequestBody RouteMatrixRequest body + ); +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/config/AzureMapsFeignConfiguration.java b/src/main/java/uk/gov/hmcts/dts/fact/config/AzureMapsFeignConfiguration.java new file mode 100644 index 000000000..5a73036ac --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/config/AzureMapsFeignConfiguration.java @@ -0,0 +1,24 @@ +package uk.gov.hmcts.dts.fact.config; + +import feign.RequestInterceptor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AzureMapsFeignConfiguration { + + @Value("${azure.maps.client-id}") + private String clientId; + + @Value("${azure.maps.subscription-key}") + private String subscriptionKey; + + @Bean + public RequestInterceptor azureMapsRequestInterceptor() { + return template -> { + template.header("x-ms-client-id", clientId); + template.query("subscription-key", subscriptionKey); + }; + } +} diff --git a/src/main/java/uk/gov/hmcts/dts/fact/controllers/SearchController.java b/src/main/java/uk/gov/hmcts/dts/fact/controllers/SearchController.java index b8b746498..fe2615a14 100644 --- a/src/main/java/uk/gov/hmcts/dts/fact/controllers/SearchController.java +++ b/src/main/java/uk/gov/hmcts/dts/fact/controllers/SearchController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import uk.gov.hmcts.dts.fact.entity.CourtByRoadDistance; import uk.gov.hmcts.dts.fact.model.CourtReferenceWithDistance; import uk.gov.hmcts.dts.fact.model.CourtWithDistance; import uk.gov.hmcts.dts.fact.model.ServiceAreaWithCourtReferencesWithDistance; @@ -90,6 +91,15 @@ public ResponseEntity> findCourtsByPostcode( return ok(courtService.getNearestCourtReferencesByPostcode(postcode)); } + @GetMapping(path = "/results/accurate/{postcode}") + public ResponseEntity> findCourtsByPostcodeAccurate(@Pattern(regexp = + "([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z]\\d{1,2})|(([A-Za-z]" + + "[A-Ha-hJ-Yj-y]\\d{1,2})|(([A-Za-z]\\d[A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y]" + + "\\d[A-Za-z]?))))\\s?\\d[A-Za-z]{2})", + message = "Provided postcode is not valid") @PathVariable String postcode) { + return ok(courtService.getCourtsByPostcodeAccurate(postcode)); + } + /** * Find courts by postcode and Service Area. * @param postcode The postcode to search for diff --git a/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtByRoadDistance.java b/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtByRoadDistance.java new file mode 100644 index 000000000..6fe317266 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtByRoadDistance.java @@ -0,0 +1,16 @@ +package uk.gov.hmcts.dts.fact.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class CourtByRoadDistance { + private Integer id; + private String name; + private String slug; + private Double lat; + private Double lon; + private Double distanceMiles; + private Double travelTimeMinutes; +} diff --git a/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtRoadDistanceCache.java b/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtRoadDistanceCache.java new file mode 100644 index 000000000..fdb661379 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/entity/CourtRoadDistanceCache.java @@ -0,0 +1,24 @@ +package uk.gov.hmcts.dts.fact.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Entity +@Table(name = "court_road_distance_cache") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CourtRoadDistanceCache { + @Id + private String postcode; + + private String responseJson; + + private Instant computedAt; +} diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/Feature.java b/src/main/java/uk/gov/hmcts/dts/fact/model/Feature.java new file mode 100644 index 000000000..664f17d6f --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/Feature.java @@ -0,0 +1,20 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Feature { + + private final String type = "Feature"; + + private Geometry geometry; + + private Map properties; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/Geometry.java b/src/main/java/uk/gov/hmcts/dts/fact/model/Geometry.java new file mode 100644 index 000000000..6a0acfb86 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/Geometry.java @@ -0,0 +1,18 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Geometry { + + private final String type = "MultiPoint"; + + private List> coordinates; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/MatrixCell.java b/src/main/java/uk/gov/hmcts/dts/fact/model/MatrixCell.java new file mode 100644 index 000000000..c2e6b68d9 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/MatrixCell.java @@ -0,0 +1,17 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.Data; + +@Data +public class MatrixCell { + + private int statusCode; + private int originIndex; + private int destinationIndex; + + private int durationInSeconds; + private int durationTrafficInSeconds; + + private double distanceInMeters; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/Properties.java b/src/main/java/uk/gov/hmcts/dts/fact/model/Properties.java new file mode 100644 index 000000000..8ab87df8d --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/Properties.java @@ -0,0 +1,13 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class Properties { + + private Summary summary; + private List matrix; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixRequest.java b/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixRequest.java new file mode 100644 index 000000000..65d5753ab --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixRequest.java @@ -0,0 +1,19 @@ +package uk.gov.hmcts.dts.fact.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.List; + +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RouteMatrixRequest { + + private final String type = "FeatureCollection"; + + private List features; + + private String travelMode = "driving"; + private String optimizeRoute = "fastest"; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixResponse.java b/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixResponse.java new file mode 100644 index 000000000..94e5cc8f6 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/RouteMatrixResponse.java @@ -0,0 +1,12 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.Data; + +@Data +public class RouteMatrixResponse { + + private String type; + private Geometry geometry; + private Properties properties; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/model/Summary.java b/src/main/java/uk/gov/hmcts/dts/fact/model/Summary.java new file mode 100644 index 000000000..cffa13b22 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/model/Summary.java @@ -0,0 +1,11 @@ +package uk.gov.hmcts.dts.fact.model; + +import lombok.Data; + +@Data +public class Summary { + + private int totalCount; + private int successfulCount; +} + diff --git a/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtRoadDistanceCacheRepository.java b/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtRoadDistanceCacheRepository.java new file mode 100644 index 000000000..4fa8a7b77 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtRoadDistanceCacheRepository.java @@ -0,0 +1,7 @@ +package uk.gov.hmcts.dts.fact.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import uk.gov.hmcts.dts.fact.entity.CourtRoadDistanceCache; + +public interface CourtRoadDistanceCacheRepository extends JpaRepository { +} diff --git a/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtWithDistanceRepository.java b/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtWithDistanceRepository.java index 2c13f89f9..d40cbaa54 100644 --- a/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtWithDistanceRepository.java +++ b/src/main/java/uk/gov/hmcts/dts/fact/repositories/CourtWithDistanceRepository.java @@ -15,6 +15,7 @@ public interface CourtWithDistanceRepository extends JpaRepository findNearestTen(@Param(LAT) Double lat, @Param(LON) Double lon); + @Query(nativeQuery = true, + value = SELECT_POINT_C_LON_C_LAT_POINT_LON_LAT_AS_DISTANCE + + FROM_SEARCH_COURT_AS_C + + WHERE_C_DISPLAYED + + "ORDER BY distance, name " + + "LIMIT 50") + List findNearestX(@Param(LAT) Double lat, @Param(LON) Double lon, @Param(LIMIT_PARAM) Integer limit); + @Query(nativeQuery = true, value = SELECT_POINT_C_LON_C_LAT_POINT_LON_LAT_AS_DISTANCE + FROM_SEARCH_COURT_AS_C diff --git a/src/main/java/uk/gov/hmcts/dts/fact/services/AzureMapsService.java b/src/main/java/uk/gov/hmcts/dts/fact/services/AzureMapsService.java new file mode 100644 index 000000000..45498ce86 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/dts/fact/services/AzureMapsService.java @@ -0,0 +1,150 @@ +package uk.gov.hmcts.dts.fact.services; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import uk.gov.hmcts.dts.fact.clients.AzureMapsRouteMatrixClient; +import uk.gov.hmcts.dts.fact.entity.CourtByRoadDistance; +import uk.gov.hmcts.dts.fact.entity.CourtRoadDistanceCache; +import uk.gov.hmcts.dts.fact.entity.CourtWithDistance; +import uk.gov.hmcts.dts.fact.exception.InvalidPostcodeException; +import uk.gov.hmcts.dts.fact.mapit.MapitData; +import uk.gov.hmcts.dts.fact.model.Feature; +import uk.gov.hmcts.dts.fact.model.Geometry; +import uk.gov.hmcts.dts.fact.model.MatrixCell; +import uk.gov.hmcts.dts.fact.model.RouteMatrixRequest; +import uk.gov.hmcts.dts.fact.model.RouteMatrixResponse; +import uk.gov.hmcts.dts.fact.repositories.CourtRoadDistanceCacheRepository; +import uk.gov.hmcts.dts.fact.repositories.CourtWithDistanceRepository; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AzureMapsService { + + private static final String API_VERSION = "2025-01-01"; + + private final CourtWithDistanceRepository courtWithDistanceRepository; + private final CourtRoadDistanceCacheRepository courtRoadDistanceCacheRepository; + private final MapitService mapitService; + private final ObjectMapper objectMapper; + + private final AzureMapsRouteMatrixClient routeMatrixClient; + + /** + * Find nearest courts by road distance. + */ + public List findNearestCourtsByRoad(String postcode, int numberOfCrowCourts) { + String normalisedPostcode = postcode.replaceAll("\\s+", "").toUpperCase(); + Optional cachedResults = courtRoadDistanceCacheRepository.findById(normalisedPostcode); + + if (cachedResults.isPresent()) { + try { + log.info("Using cached results"); + JavaType type = objectMapper.getTypeFactory() + .constructCollectionType(List.class, CourtByRoadDistance.class); + return objectMapper.readValue(cachedResults.get().getResponseJson(), type); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error deserializing court road distance results", e); + } + } + + MapitData origin = mapitService.getMapitData(postcode).orElseThrow(() -> new InvalidPostcodeException(postcode)); + + List crowFlightCourts = courtWithDistanceRepository.findNearestX( + origin.getLat(), + origin.getLon(), + numberOfCrowCourts + ); + + RouteMatrixResponse matrix = calculateRoadDistances(origin, crowFlightCourts); + List results = mapMatrixToResults(matrix, crowFlightCourts); + + List sortedResults = results.stream() + .sorted(Comparator.comparingDouble(CourtByRoadDistance::getDistanceMiles)) + .limit(10) + .toList(); + + storeResultsForPostcode(normalisedPostcode, sortedResults); + + return sortedResults; + } + + /** + * Call Azure Maps Route Matrix (2025-01-01) via Feign. + */ + private RouteMatrixResponse calculateRoadDistances(MapitData origin, List courts) { + Feature originFeature = new Feature(new Geometry(List.of(List.of(origin.getLon(), origin.getLat()))), + Map.of("pointType", "origins")); + + List> destinationCoords = courts.stream() + .map(c -> List.of(c.getLon(), c.getLat())) + .toList(); + + Feature destinationsFeature = new Feature(new Geometry(destinationCoords), Map.of("pointType", "destinations")); + + RouteMatrixRequest request = new RouteMatrixRequest(); + request.setFeatures(List.of(originFeature, destinationsFeature)); + log.info("Calling Azure Maps Route Matrix"); + return routeMatrixClient.calculateMatrix( + API_VERSION, + request + ); + } + + /** + * Map the new Matrix response to CourtByRoadDistance. + */ + private List mapMatrixToResults(RouteMatrixResponse response, List courts) { + List results = new ArrayList<>(); + + for (MatrixCell cell : response.getProperties().getMatrix()) { + if (cell.getStatusCode() != 200) { + log.warn( + "RouteMatrix cell failed: destinationIndex={}, statusCode={}", + cell.getDestinationIndex(), + cell.getStatusCode() + ); + continue; + } + + CourtWithDistance court = courts.get(cell.getDestinationIndex()); + + results.add(new CourtByRoadDistance( + court.getId(), + court.getName(), + court.getSlug(), + court.getLat(), + court.getLon(), + cell.getDistanceInMeters() * 0.000621371, + cell.getDurationInSeconds() / 60.0 + )); + } + + return results; + } + + private void storeResultsForPostcode(String postcode, List results) { + try { + courtRoadDistanceCacheRepository.save( + new CourtRoadDistanceCache( + postcode, + objectMapper.writeValueAsString(results), + Instant.now() + ) + ); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error serializing court road distance results", e); + } + } +} diff --git a/src/main/java/uk/gov/hmcts/dts/fact/services/CourtService.java b/src/main/java/uk/gov/hmcts/dts/fact/services/CourtService.java index 420aef9d8..22438ab29 100644 --- a/src/main/java/uk/gov/hmcts/dts/fact/services/CourtService.java +++ b/src/main/java/uk/gov/hmcts/dts/fact/services/CourtService.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import uk.gov.hmcts.dts.fact.entity.CourtByRoadDistance; import uk.gov.hmcts.dts.fact.entity.ServiceArea; import uk.gov.hmcts.dts.fact.exception.InvalidPostcodeException; import uk.gov.hmcts.dts.fact.exception.NotFoundException; @@ -55,6 +56,7 @@ public class CourtService { private final FallbackProximitySearch fallbackProximitySearch; private final CourtHistoryRepository courtHistoryRepository; + private final AzureMapsService azureMapsService; /** * Constructor for the CourtService. @@ -76,7 +78,7 @@ public CourtService(final MapitService mapitService, final ServiceAreaRepository serviceAreaRepository, final ServiceAreaSearchFactory serviceAreaSearchFactory, final FallbackProximitySearch fallbackProximitySearch, - final CourtHistoryRepository courtHistoryRepository) { + final CourtHistoryRepository courtHistoryRepository, AzureMapsService azureMapsService) { this.mapitService = mapitService; this.courtWithDistanceRepository = courtWithDistanceRepository; this.proximitySearch = proximitySearch; @@ -85,6 +87,7 @@ public CourtService(final MapitService mapitService, this.serviceAreaSearchFactory = serviceAreaSearchFactory; this.fallbackProximitySearch = fallbackProximitySearch; this.courtHistoryRepository = courtHistoryRepository; + this.azureMapsService = azureMapsService; } /** @@ -231,6 +234,10 @@ public List getNearestCourtReferencesByPostcode(fina return courtReferences; } + public List getCourtsByPostcodeAccurate(String postcode) { + return azureMapsService.findNearestCourtsByRoad(postcode, 50); + } + public ServiceAreaWithCourtReferencesWithDistance getNearestCourtsByPostcodeSearch(final String postcode, final String serviceAreaSlug, final Boolean includeClosed, diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index a646b3a59..a97bb4bf8 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -77,3 +77,9 @@ resilience4j: limitForPeriod: 15 limitRefreshPeriod: 1s timeoutDuration: 3s + + +azure-maps: + client-id: ${AZURE_MAPS_CLIENT_ID:} + subscription-key: ${AZURE_MAPS_SUBSCRIPTION_KEY:} + diff --git a/src/main/resources/db/migration/V215__cache_postcode_results.sql b/src/main/resources/db/migration/V215__cache_postcode_results.sql new file mode 100644 index 000000000..ec0f587d9 --- /dev/null +++ b/src/main/resources/db/migration/V215__cache_postcode_results.sql @@ -0,0 +1,5 @@ +CREATE TABLE court_road_distance_cache ( + postcode VARCHAR(16) PRIMARY KEY, + response_json TEXT NOT NULL, + computed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +);