feat #461: add operational status dashboard

This commit is contained in:
devmrko
2026-06-25 21:55:26 +09:00
parent 1869fe46a6
commit 2379e2c9ec
8 changed files with 372 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
package com.cloudhandson.vpdbackoffice.domain.operation;
public record OperationStatusRow(
long objectId,
String owner,
String objectName,
String ordsPath,
String enabledYn,
Integer permissionCount,
Integer ruleCount,
String policyNames,
String policyEnabled,
String functionName,
String functionStatus,
Long handlerId,
String handlerMethod,
String handlerSourceType,
String handlerFullPath,
String lastProbeStatus,
Integer lastProbeRowCount,
String lastProbeErrorCode,
String lastProbeAt
) {
public String displayName() {
return owner + "." + objectName;
}
public String healthLevel() {
if (functionStatus != null && !"VALID".equalsIgnoreCase(functionStatus)) {
return "ERROR";
}
if (handlerId == null || policyNames == null || policyNames.isBlank()
|| policyEnabled == null || !policyEnabled.toUpperCase().contains("YES")) {
return "WARN";
}
if (lastProbeStatus != null && !lastProbeStatus.isBlank()
&& !lastProbeStatus.toUpperCase().contains("SUCCESS")
&& !lastProbeStatus.toUpperCase().contains("ALLOW")) {
return "WARN";
}
return "OK";
}
public String actionText() {
if (handlerId == null) {
return "ORDS path와 handler schema/module/template 매핑을 확인하세요.";
}
if (policyNames == null || policyNames.isBlank()) {
return "VPD policy를 적용하세요.";
}
if (policyEnabled == null || !policyEnabled.toUpperCase().contains("YES")) {
return "VPD policy enable 상태를 확인하세요.";
}
if (functionStatus != null && !"VALID".equalsIgnoreCase(functionStatus)) {
return "Policy function 컴파일 오류를 확인하세요.";
}
if (lastProbeStatus == null || lastProbeStatus.isBlank()) {
return "ORDS 검증을 한 번 실행하세요.";
}
return "현재 상태에서 즉시 조치할 항목은 없습니다.";
}
public String permissionSummary() {
int permissions = permissionCount == null ? 0 : permissionCount;
int rules = ruleCount == null ? 0 : ruleCount;
return permissions + " permissions / " + rules + " rules";
}
}

View File

@@ -0,0 +1,11 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.operation.OperationStatusRow;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OperationStatusMapper {
List<OperationStatusRow> findRows();
}

View File

@@ -0,0 +1,20 @@
package com.cloudhandson.vpdbackoffice.service;
import com.cloudhandson.vpdbackoffice.domain.operation.OperationStatusRow;
import com.cloudhandson.vpdbackoffice.mapper.OperationStatusMapper;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class OperationStatusService {
private final OperationStatusMapper mapper;
public OperationStatusService(OperationStatusMapper mapper) {
this.mapper = mapper;
}
public List<OperationStatusRow> findRows() {
return mapper.findRows();
}
}

View File

@@ -0,0 +1,22 @@
package com.cloudhandson.vpdbackoffice.web;
import com.cloudhandson.vpdbackoffice.service.OperationStatusService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class OperationStatusController {
private final OperationStatusService service;
public OperationStatusController(OperationStatusService service) {
this.service = service;
}
@GetMapping("/operation-status")
public String status(Model model) {
model.addAttribute("rows", service.findRows());
return "operation-status";
}
}