refactor(ocr): move repository access from OcrController into OcrService

OcrController was injecting OcrJobRepository and OcrJobDocumentRepository
directly, violating the Controller → Service → Repository layering rule.
Moved getJob() and getDocumentOcrStatus() logic into OcrService.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-13 12:26:14 +02:00
parent 410ef88e1a
commit 2d43f09172
4 changed files with 105 additions and 41 deletions

View File

@@ -5,11 +5,8 @@ import lombok.extern.slf4j.Slf4j;
import org.raddatz.familienarchiv.dto.BatchOcrDTO;
import org.raddatz.familienarchiv.dto.OcrStatusDTO;
import org.raddatz.familienarchiv.dto.TriggerOcrDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.model.*;
import org.raddatz.familienarchiv.repository.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.repository.OcrJobRepository;
import org.raddatz.familienarchiv.model.AppUser;
import org.raddatz.familienarchiv.model.OcrJob;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.raddatz.familienarchiv.service.OcrBatchService;
@@ -23,9 +20,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@RestController
@@ -36,8 +31,6 @@ public class OcrController {
private final OcrService ocrService;
private final OcrBatchService ocrBatchService;
private final OcrProgressService ocrProgressService;
private final OcrJobRepository ocrJobRepository;
private final OcrJobDocumentRepository ocrJobDocumentRepository;
private final UserService userService;
@PostMapping("/api/documents/{documentId}/ocr")
@@ -66,40 +59,20 @@ public class OcrController {
@GetMapping("/api/ocr/jobs/{jobId}")
@RequirePermission(Permission.READ_ALL)
public OcrJob getJobStatus(@PathVariable UUID jobId) {
return ocrJobRepository.findById(jobId)
.orElseThrow(() -> DomainException.notFound(
ErrorCode.OCR_JOB_NOT_FOUND, "OCR job not found: " + jobId));
return ocrService.getJob(jobId);
}
@GetMapping(value = "/api/ocr/jobs/{jobId}/progress", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@RequirePermission(Permission.READ_ALL)
public SseEmitter streamProgress(@PathVariable UUID jobId) {
ocrJobRepository.findById(jobId)
.orElseThrow(() -> DomainException.notFound(
ErrorCode.OCR_JOB_NOT_FOUND, "OCR job not found: " + jobId));
ocrService.getJob(jobId);
return ocrProgressService.register(jobId);
}
@GetMapping("/api/documents/{documentId}/ocr-status")
@RequirePermission(Permission.READ_ALL)
public OcrStatusDTO getDocumentOcrStatus(@PathVariable UUID documentId) {
List<OcrDocumentStatus> activeStatuses = List.of(
OcrDocumentStatus.PENDING, OcrDocumentStatus.RUNNING);
Optional<OcrJobDocument> activeJobDoc = ocrJobDocumentRepository
.findFirstByDocumentIdAndStatusIn(documentId, activeStatuses);
if (activeJobDoc.isEmpty()) {
return OcrStatusDTO.builder().status("NONE").build();
}
OcrJobDocument jobDoc = activeJobDoc.get();
return OcrStatusDTO.builder()
.status(jobDoc.getStatus().name())
.jobId(jobDoc.getJobId())
.currentPage(jobDoc.getCurrentPage())
.totalPages(jobDoc.getTotalPages())
.build();
return ocrService.getDocumentOcrStatus(documentId);
}
private UUID resolveUserId(Authentication authentication) {

View File

@@ -2,6 +2,7 @@ package org.raddatz.familienarchiv.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.raddatz.familienarchiv.dto.OcrStatusDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.model.*;
@@ -9,6 +10,8 @@ import org.raddatz.familienarchiv.repository.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.repository.OcrJobRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Service
@@ -22,6 +25,32 @@ public class OcrService {
private final OcrJobDocumentRepository ocrJobDocumentRepository;
private final OcrAsyncRunner ocrAsyncRunner;
public OcrJob getJob(UUID jobId) {
return ocrJobRepository.findById(jobId)
.orElseThrow(() -> DomainException.notFound(
ErrorCode.OCR_JOB_NOT_FOUND, "OCR job not found: " + jobId));
}
public OcrStatusDTO getDocumentOcrStatus(UUID documentId) {
List<OcrDocumentStatus> activeStatuses = List.of(
OcrDocumentStatus.PENDING, OcrDocumentStatus.RUNNING);
Optional<OcrJobDocument> activeJobDoc = ocrJobDocumentRepository
.findFirstByDocumentIdAndStatusIn(documentId, activeStatuses);
if (activeJobDoc.isEmpty()) {
return OcrStatusDTO.builder().status("NONE").build();
}
OcrJobDocument jobDoc = activeJobDoc.get();
return OcrStatusDTO.builder()
.status(jobDoc.getStatus().name())
.jobId(jobDoc.getJobId())
.currentPage(jobDoc.getCurrentPage())
.totalPages(jobDoc.getTotalPages())
.build();
}
public UUID startOcr(UUID documentId, ScriptType scriptTypeOverride, UUID userId) {
Document doc = documentService.getDocumentById(documentId);