package com.lincfusion.udyamlinc.ingestion; import com.lincfusion.udyamlinc.common.ApiResponse; import com.lincfusion.udyamlinc.master.District; import com.lincfusion.udyamlinc.master.DistrictRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.web.bind.annotation.*; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * The operations surface for ingestion: what ran, what it fetched, and how stale * each district's data now is. * *
Mounted under {@code /admin} so the existing rule applies — any officer may
* read, only a supervisor may trigger a run.
*/
@RestController
@RequestMapping("/admin/ingestion")
@RequiredArgsConstructor
public class IngestionController {
private final IngestionScheduler scheduler;
private final IngestionRunRepository runRepository;
private final MarketSignalRepository marketSignalRepository;
private final ClimateSignalRepository climateSignalRepository;
private final ApiLogRepository apiLogRepository;
private final DistrictRepository districtRepository;
// ── what ran ────────────────────────────────────────────
@GetMapping("/runs")
public ApiResponse> runs(@RequestParam(required = false) String source,
@RequestParam(defaultValue = "30") int limit) {
PageRequest page = PageRequest.of(0, Math.min(limit, 200));
return ApiResponse.ok(source == null
? runRepository.findAllByOrderByStartedAtDesc(page)
: runRepository.findBySourceOrderByStartedAtDesc(source, page));
}
@GetMapping("/calls")
public ApiResponse
> calls(@RequestParam(required = false) String source,
@RequestParam(defaultValue = "50") int limit) {
PageRequest page = PageRequest.of(0, Math.min(limit, 200));
return ApiResponse.ok(source == null
? apiLogRepository.findAllByOrderByCalledAtDesc(page)
: apiLogRepository.findBySourceOrderByCalledAtDesc(source, page));
}
// ── what it wrote ───────────────────────────────────────
@GetMapping("/signals/market")
public ApiResponse
> marketSignals(@RequestParam(defaultValue = "12") int weeks) {
return ApiResponse.ok(marketSignalRepository
.findByWeekStartGreaterThanEqualOrderByWeekStartDesc(Weeks.startOf(LocalDate.now()).minusWeeks(weeks)));
}
@GetMapping("/signals/climate")
public ApiResponse
> climateSignals(@RequestParam(defaultValue = "12") int weeks) {
return ApiResponse.ok(climateSignalRepository
.findByWeekStartGreaterThanEqualOrderByWeekStartDesc(Weeks.startOf(LocalDate.now()).minusWeeks(weeks)));
}
/**
* Per-district freshness — the number a trip-wire consults before it is
* allowed to fire. A rule firing on a three-week-old price is worse than no
* rule.
*/
@GetMapping("/freshness")
public ApiResponse
>> freshness() {
LocalDate today = LocalDate.now();
List