backend: правки complex-mission/mission-planing/request + тестовые паспорта

ComplexPlanRunOrchestrationService, MissionController, MissionPlaningService,
KafkaProducerConfig; обновлены тестовые JSON-паспорта route-processing.
This commit is contained in:
Дмитрий Соловьев
2026-06-06 00:04:17 +03:00
parent b454c01c09
commit 1d07588690
6 changed files with 64 additions and 27 deletions
@@ -10,6 +10,7 @@ import space.nstart.pcp.pcp_satellites_service.entity.ComplexPlanRunEntity
import space.nstart.pcp.pcp_types_lib.dto.requests.ComplexPlanProcessRequestDTO import space.nstart.pcp.pcp_types_lib.dto.requests.ComplexPlanProcessRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.requests.CoverageCalculationSource import space.nstart.pcp.pcp_types_lib.dto.requests.CoverageCalculationSource
import tools.jackson.databind.json.JsonMapper import tools.jackson.databind.json.JsonMapper
import java.time.Duration
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@Service @Service
@@ -25,6 +26,8 @@ class ComplexPlanRunOrchestrationService(
private val objectMapper = JsonMapper.builder().findAndAddModules().build() private val objectMapper = JsonMapper.builder().findAndAddModules().build()
fun process(request: ComplexPlanProcessRequestDTO, requestedBy: String?): ComplexPlanRunResponseDTO { fun process(request: ComplexPlanProcessRequestDTO, requestedBy: String?): ComplexPlanRunResponseDTO {
validateInterval(request)
lateinit var selectedSatelliteIds: List<Long> lateinit var selectedSatelliteIds: List<Long>
val resolveSatelliteIdsMs = measureTimeMillis { val resolveSatelliteIdsMs = measureTimeMillis {
selectedSatelliteIds = resolveSatelliteIds(request) selectedSatelliteIds = resolveSatelliteIds(request)
@@ -161,6 +164,25 @@ class ComplexPlanRunOrchestrationService(
request.satelliteId?.let { add(it) } request.satelliteId?.let { add(it) }
addAll(request.satelliteIds) addAll(request.satelliteIds)
}.distinct().ifEmpty { satelliteService.satellites.map { it.satelliteId }.distinct() } }.distinct().ifEmpty { satelliteService.satellites.map { it.satelliteId }.distinct() }
/**
* Интервал расчёта обязан быть корректным и не длиннее [MAX_INTERVAL_DAYS] суток: считать
* комплексный план по всем КА на больший горизонт слишком тяжело и бессмысленно для оперативного
* плана. Проверка до создания run, чтобы не плодить заведомо отклонённые записи.
*/
private fun validateInterval(request: ComplexPlanProcessRequestDTO) {
if (!request.intervalEnd.isAfter(request.intervalStart)) {
throw CustomValidationException("Interval end must be after interval start")
}
if (Duration.between(request.intervalStart, request.intervalEnd) > Duration.ofDays(MAX_INTERVAL_DAYS)) {
throw CustomValidationException("Complex plan interval cannot exceed $MAX_INTERVAL_DAYS days")
}
}
companion object {
/** Максимальная длина интервала расчёта комплексного плана, суток. */
const val MAX_INTERVAL_DAYS = 10L
}
} }
data class ComplexPlanCalculationResult( data class ComplexPlanCalculationResult(
@@ -253,10 +253,12 @@ class MissionController(
} }
@Operation( @Operation(
summary = "Полностью очистить план", summary = "Очистить включения плана",
description = "Удаляет ВСЕ включения плана миссии: съёмки (включая построенные вручную, source=MANUAL) " + description = "Удаляет включения плана миссии вместе с бронями слотов и связями съёмка↔сброс. " +
"и сбросы, вместе с бронями слотов и связями съёмка↔сброс. В отличие от пересчёта плана, " + "Сбросы удаляются всегда. Для съёмок поведение выбирает оператор флагом keepManual: " +
"ручные маршруты тоже удаляются. Используется кнопкой «Очистить план» в редакторе." "keepManual=true — ручные маршруты съёмки (source=MANUAL) сохраняются, удаляются только " +
"рассчитанные (как при пересчёте плана); keepManual=false (по умолчанию) — удаляются ВСЕ " +
"съёмки, включая ручные. Используется кнопкой «Очистить план» в редакторе."
) )
@ApiResponses( @ApiResponses(
value = [ value = [
@@ -267,9 +269,11 @@ class MissionController(
@DeleteMapping("/{mission_id}/modes") @DeleteMapping("/{mission_id}/modes")
fun clearPlan( fun clearPlan(
@Parameter(description = "Идентификатор миссии") @Parameter(description = "Идентификатор миссии")
@PathVariable("mission_id") id: UUID @PathVariable("mission_id") id: UUID,
@Parameter(description = "Сохранить ручные маршруты съёмки (source=MANUAL)")
@RequestParam(name = "keepManual", required = false, defaultValue = "false") keepManual: Boolean
): ResponseEntity<Void> { ): ResponseEntity<Void> {
missionPlaningService.clearPlan(id) missionPlaningService.clearPlan(id, keepManual)
return ResponseEntity.noContent().build() return ResponseEntity.noContent().build()
} }
@@ -937,18 +937,29 @@ class MissionPlaningService(
} }
/** /**
* Полная очистка плана: удаляет ВСЕ включения миссии — съёмки (включая ручные, source=MANUAL) * Очистка плана. Всегда удаляет все сбросы и брони слотов; для съёмок поведение выбирает
* и сбросы — вместе с бронями слотов и связями съёмка↔сброс. В отличие от пересчёта плана * оператор флагом [keepManual]:
* ([loadSlots]/[calculateDrops]), ручные маршруты тоже удаляются. Сбросы удаляются первыми, * - `keepManual=true` — сохраняются ручные маршруты съёмки (source=MANUAL), удаляются только
* чтобы снять связи до удаления съёмок и не плодить проверку осиротевших сбросов. * рассчитанные (как и при пересчёте плана [loadSlots]/[calculateDrops]);
* - `keepManual=false` — удаляются ВСЕ съёмки, включая ручные (полная очистка).
* Сбросы удаляются первыми, чтобы снять связи до удаления съёмок и не плодить проверку
* осиротевших сбросов.
*/ */
@Transactional @Transactional
fun clearPlan(missionId: UUID) { fun clearPlan(missionId: UUID, keepManual: Boolean) {
missionRepository.findById(missionId).orElseThrow { notFound(missionId) } missionRepository.findById(missionId).orElseThrow { notFound(missionId) }
val modes = modeRepository.findAllByPlan_Mission_MissionIdOrderByTimeStartAsc(missionId) val modes = modeRepository.findAllByPlan_Mission_MissionIdOrderByTimeStartAsc(missionId)
modes.filterIsInstance<DropModeEntity>().forEach { deleteDropMode(it) } val drops = modes.filterIsInstance<DropModeEntity>()
modes.filterIsInstance<SurveyModeEntity>().forEach { deleteSurveyMode(it) } val surveys = modes.filterIsInstance<SurveyModeEntity>()
logger.info("План миссии {} полностью очищен: удалено включений={}", missionId, modes.size) val (keptSurveys, deletedSurveys) =
if (keepManual) surveys.partition { it.source == SurveyModeSource.MANUAL }
else emptyList<SurveyModeEntity>() to surveys
drops.forEach { deleteDropMode(it) }
deletedSurveys.forEach { deleteSurveyMode(it) }
logger.info(
"План миссии {} очищен (keepManual={}): удалено сбросов={}, съёмок={}, сохранено ручных съёмок (MANUAL)={}",
missionId, keepManual, drops.size, deletedSurveys.size, keptSurveys.size
)
} }
/** /**
@@ -15,7 +15,7 @@ class KafkaProducerConfig {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
fun requestProducerFactory( fun requestProducerFactory(
@Value("\${spring.kafka.bootstrap-servers:192.168.100.160:19092}") bootstrapServers: String, @Value("\${spring.kafka.bootstrap-servers:localhost:29092}") bootstrapServers: String,
): ProducerFactory<String, String> { ): ProducerFactory<String, String> {
return DefaultKafkaProducerFactory( return DefaultKafkaProducerFactory(
mapOf( mapOf(
@@ -98,7 +98,7 @@
], ],
"assets": { "assets": {
"schema-calibration-vh": { "schema-calibration-vh": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/calibration-s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=26988c6a3490f71382ae9e61ff0d7b59aca32ec652993a785d24e8dd81e70939", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/calibration-s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=26988c6a3490f71382ae9e61ff0d7b59aca32ec652993a785d24e8dd81e70939",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -107,7 +107,7 @@
] ]
}, },
"schema-calibration-vv": { "schema-calibration-vv": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/calibration-s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=edd6957a0404ead07e7a31d0759db26b3a6ad33394247c177dc41a7abf5972d0", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/calibration-s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=edd6957a0404ead07e7a31d0759db26b3a6ad33394247c177dc41a7abf5972d0",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -116,7 +116,7 @@
] ]
}, },
"schema-noise-vh": { "schema-noise-vh": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/noise-s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=3efe46114ed6dfeac898963510d3ba9c8b537c803b1fa69a5a03d5b462a1665c", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/noise-s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=3efe46114ed6dfeac898963510d3ba9c8b537c803b1fa69a5a03d5b462a1665c",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -125,7 +125,7 @@
] ]
}, },
"schema-noise-vv": { "schema-noise-vv": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/noise-s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=0ca91479ba4132dbf13c2637f97567eb29ee9ca818009eaf501072995fe784ca", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/noise-s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120818Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=0ca91479ba4132dbf13c2637f97567eb29ee9ca818009eaf501072995fe784ca",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -134,7 +134,7 @@
] ]
}, },
"schema-product-vh": { "schema-product-vh": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=39817f0b7610c0b20a23d0fae24e7183f0d3719ba6ab2f315c320c9c6530274f", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=39817f0b7610c0b20a23d0fae24e7183f0d3719ba6ab2f315c320c9c6530274f",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -143,7 +143,7 @@
] ]
}, },
"schema-product-vv": { "schema-product-vv": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=85d28bc2bb94724b4db7df84121d4252b423fa429204e4b25e06b9d725f3aeee", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=85d28bc2bb94724b4db7df84121d4252b423fa429204e4b25e06b9d725f3aeee",
"title": "xml", "title": "xml",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -152,7 +152,7 @@
] ]
}, },
"safe-manifest": { "safe-manifest": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/manifest.safe?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=dbb22d57d031a412e2b46273edf32cfcb7fbdae1fa1fcc74bdcaa39a5e086f53", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/manifest.safe?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120819Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=dbb22d57d031a412e2b46273edf32cfcb7fbdae1fa1fcc74bdcaa39a5e086f53",
"title": "safe", "title": "safe",
"description": null, "description": null,
"type": "application/xml", "type": "application/xml",
@@ -161,7 +161,7 @@
] ]
}, },
"vh": { "vh": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002_cog.tif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120824Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=dbecc9e04e976751e855f53e9a9a8db5d6365a30ac7ec116f31b0936ee375648", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vh-20250625t013854-20250625t013919-059796-076d15-002_cog.tif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120824Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=dbecc9e04e976751e855f53e9a9a8db5d6365a30ac7ec116f31b0936ee375648",
"title": "tif", "title": "tif",
"description": null, "description": null,
"type": "image/tiff; application=geotiff; profile=cloud-optimized", "type": "image/tiff; application=geotiff; profile=cloud-optimized",
@@ -170,7 +170,7 @@
] ]
}, },
"vv": { "vv": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001_cog.tif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=34cf1e5f5174b7cb5ca5d173ff699923819d5df28486436d972efa59ac9b1ddb", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/s1a-iw-grd-vv-20250625t013854-20250625t013919-059796-076d15-001_cog.tif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=34cf1e5f5174b7cb5ca5d173ff699923819d5df28486436d972efa59ac9b1ddb",
"title": "tif", "title": "tif",
"description": null, "description": null,
"type": "image/tiff; application=geotiff; profile=cloud-optimized", "type": "image/tiff; application=geotiff; profile=cloud-optimized",
@@ -179,7 +179,7 @@
] ]
}, },
"kml": { "kml": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/map-overlay.kml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=92f63b9f463041c4ed87b3cb508ba8c57fd2db8ea2d22026087ba57d2ef88f54", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/map-overlay.kml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=92f63b9f463041c4ed87b3cb508ba8c57fd2db8ea2d22026087ba57d2ef88f54",
"title": "kml", "title": "kml",
"description": null, "description": null,
"type": "application/kml", "type": "application/kml",
@@ -188,7 +188,7 @@
] ]
}, },
"thumbnail": { "thumbnail": {
"href": "http://192.168.60.201:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/quick-look.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=19bebb1e446add1d6e0898b4329d2a3e016f59087719ce2b51dff5c487835cb0", "href": "http://192.168.60.146:9000/stac-data/S1A/S1A_IW_GRDH_1SDV_20250625T013854_20250625T013919_059796_076D15_B5C1.SAFE/quick-look.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T120829Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=19bebb1e446add1d6e0898b4329d2a3e016f59087719ce2b51dff5c487835cb0",
"title": "png", "title": "png",
"description": null, "description": null,
"type": "image/png", "type": "image/png",
File diff suppressed because one or more lines are too long