refs #741 #742: reorganize repository by application

This commit is contained in:
devmrko
2026-08-03 10:20:36 +09:00
parent 2e44ed0b97
commit e9d50e6a32
445 changed files with 1523 additions and 1885 deletions

View File

@@ -1,14 +0,0 @@
package com.cloudhandson.vpdbackoffice;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.cloudhandson.vpdbackoffice.mapper")
@SpringBootApplication
public class VpdBackofficeApplication {
public static void main(String[] args) {
SpringApplication.run(VpdBackofficeApplication.class, args);
}
}

View File

@@ -1,23 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import java.time.Clock;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties({
BackofficeProperties.class,
CatalogProperties.class,
MaskingProperties.class,
McpProperties.class,
ProductProperties.class,
SecuritySqlScriptProperties.class
})
public class AppConfig {
@Bean
Clock clock() {
return Clock.systemUTC();
}
}

View File

@@ -1,102 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "backoffice")
public record BackofficeProperties(
Security security,
Token token,
Ords ords,
Ai ai,
SelectAi selectAi
) {
public record Security(
String adminUser,
String adminPassword,
String adminPasswordHash,
boolean guestEnabled,
String guestUser,
String guestPassword,
String guestPasswordHash,
boolean requireHttps,
boolean rememberMeEnabled,
String rememberMeKey,
int rememberMeDays
) {
/** Remember-me is intentionally unavailable over HTTP or without a stable secret key. */
public boolean rememberMeConfigured() {
return requireHttps
&& rememberMeEnabled
&& rememberMeKey != null
&& !rememberMeKey.isBlank()
&& rememberMeDays >= 1
&& rememberMeDays <= 90;
}
public int rememberMeValiditySeconds() {
return rememberMeDays * 24 * 60 * 60;
}
public boolean guestConfigured() {
return guestEnabled
&& guestUser != null
&& !guestUser.isBlank()
&& ((guestPassword != null && !guestPassword.isBlank())
|| (guestPasswordHash != null && !guestPasswordHash.isBlank()));
}
}
public record Token(int maxDays) {
}
public record Ords(String baseUrl, Duration timeout, Duration agentTimeout) {
}
public record Ai(
boolean enabled,
String provider,
String baseUrl,
String model,
String apiKey,
Duration timeout,
String embeddingModel,
String ociConfigFile,
String ociProfile,
String ociRegion,
String ociCompartmentId
) {
public Ai(boolean enabled, String baseUrl, String model, String apiKey, Duration timeout) {
this(enabled, "openai", baseUrl, model, apiKey, timeout, "", "", "", "", "");
}
}
/** Separate ADB connection because Select AI profiles are owned by a schema-specific account. */
public record SelectAi(
String dbUrl,
String dbUsername,
String dbPassword,
String profile,
String runtimeDbUrl,
String runtimeDbUsername,
String runtimeDbPassword
) {
public boolean configured() {
return dbUrl != null && !dbUrl.isBlank()
&& dbUsername != null && !dbUsername.isBlank()
&& dbPassword != null && !dbPassword.isBlank()
&& profile != null && !profile.isBlank();
}
/** The generated SQL must never fall back to the privileged profile-owner connection. */
public boolean runtimeConfigured() {
return runtimeDbUrl != null && !runtimeDbUrl.isBlank()
&& runtimeDbUsername != null && !runtimeDbUsername.isBlank()
&& runtimeDbPassword != null && !runtimeDbPassword.isBlank();
}
}
}

View File

@@ -1,8 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** Deployment-provided allow-list for the structured-data and metadata screens. */
@ConfigurationProperties(prefix = "backoffice.catalog")
public record CatalogProperties(String owner, String objects) {
}

View File

@@ -1,56 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import com.cloudhandson.vpdbackoffice.service.PermissionService;
import com.cloudhandson.vpdbackoffice.service.GroupService;
import com.cloudhandson.vpdbackoffice.service.UserService;
import java.sql.Connection;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class DbPoolWarmup {
private static final Logger log = LoggerFactory.getLogger(DbPoolWarmup.class);
private final DataSource dataSource;
private final UserService userService;
private final GroupService groupService;
private final PermissionService permissionService;
public DbPoolWarmup(
DataSource dataSource,
UserService userService,
GroupService groupService,
PermissionService permissionService
) {
this.dataSource = dataSource;
this.userService = userService;
this.groupService = groupService;
this.permissionService = permissionService;
}
@EventListener(ApplicationReadyEvent.class)
public void warmup() {
try (Connection ignored = dataSource.getConnection()) {
log.info("Backoffice DB pool warmed up");
warmupBackofficeCatalog();
} catch (Exception exception) {
log.warn("Backoffice DB pool warm-up failed: {}", exception.getMessage());
}
}
private void warmupBackofficeCatalog() {
long started = System.nanoTime();
userService.findAll();
userService.findUserRoles();
groupService.findAll();
groupService.findGroupUsers();
groupService.findGroupRoles();
permissionService.findRoles();
permissionService.findPermissionViews();
log.info("HMM identity catalog cache warmed up in {}ms", (System.nanoTime() - started) / 1_000_000);
}
}

View File

@@ -1,8 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** JSON configuration of database redaction policies this backoffice may manage. */
@ConfigurationProperties(prefix = "backoffice.masking")
public record MaskingProperties(String policies) {
}

View File

@@ -1,54 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** Product-neutral MCP endpoint labels and tool catalogue configuration. */
@ConfigurationProperties(prefix = "backoffice.mcp")
public record McpProperties(
String publicUrl,
String serverName,
String toolName,
String toolLabel,
String toolDescription,
String promptDescription,
String tools
) {
private static final String DEFAULT_PUBLIC_URL = "/mcp";
private static final String DEFAULT_SERVER_NAME = "data-ai-backoffice";
private static final String DEFAULT_TOOL_NAME = "oracle.select_ai.data_text2sql";
private static final String DEFAULT_TOOL_LABEL = "업무 데이터 Text2SQL";
private static final String DEFAULT_TOOL_DESCRIPTION =
"승인된 업무 데이터용 읽기 전용 SELECT/WITH SQL을 생성하고, 검증 후 읽기 전용 "
+ "트랜잭션에서 실행합니다.";
private static final String DEFAULT_PROMPT_DESCRIPTION =
"업무 데이터에서 조회할 내용을 자연어로 입력합니다.";
public String resolvedPublicUrl() {
return requiredOrDefault(publicUrl, DEFAULT_PUBLIC_URL);
}
public String resolvedServerName() {
return requiredOrDefault(serverName, DEFAULT_SERVER_NAME);
}
public String resolvedToolName() {
return requiredOrDefault(toolName, DEFAULT_TOOL_NAME);
}
public String resolvedToolLabel() {
return requiredOrDefault(toolLabel, DEFAULT_TOOL_LABEL);
}
public String resolvedToolDescription() {
return requiredOrDefault(toolDescription, DEFAULT_TOOL_DESCRIPTION);
}
public String resolvedPromptDescription() {
return requiredOrDefault(promptDescription, DEFAULT_PROMPT_DESCRIPTION);
}
private String requiredOrDefault(String value, String fallback) {
return value == null || value.isBlank() ? fallback : value.trim();
}
}

View File

@@ -1,29 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import java.time.Duration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class OrdsClientConfig {
@Bean
RestTemplate ordsRestTemplate(BackofficeProperties properties) {
Duration timeout = properties.ords().timeout();
return new RestTemplateBuilder()
.setConnectTimeout(timeout)
.setReadTimeout(timeout)
.build();
}
@Bean
RestTemplate ordsAgentRestTemplate(BackofficeProperties properties) {
Duration timeout = properties.ords().agentTimeout();
return new RestTemplateBuilder()
.setConnectTimeout(timeout)
.setReadTimeout(timeout)
.build();
}
}

View File

@@ -1,20 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** Customer-facing labels that do not affect authorization or database identity. */
@ConfigurationProperties(prefix = "backoffice.product")
public record ProductProperties(String name, String title, String dataLabel) {
public String displayName() {
return name == null || name.isBlank() ? "Data & AI Backoffice" : name.trim();
}
public String pageTitle() {
return title == null || title.isBlank() ? displayName() : title.trim();
}
public String dataName() {
return dataLabel == null || dataLabel.isBlank() ? "업무 데이터" : dataLabel.trim();
}
}

View File

@@ -1,107 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(
HttpSecurity http,
BackofficeProperties properties,
UserDetailsService userDetailsService
) throws Exception {
if (properties.security().requireHttps()) {
http.requiresChannel(channel -> channel.anyRequest().requiresSecure());
}
var security = properties.security();
if (security.rememberMeConfigured()) {
http.rememberMe(rememberMe -> rememberMe
.key(security.rememberMeKey())
.userDetailsService(userDetailsService)
.rememberMeParameter("remember-me")
.rememberMeCookieName("VPD_REMEMBER_ME")
.tokenValiditySeconds(security.rememberMeValiditySeconds())
.useSecureCookie(true)
.alwaysRemember(false));
}
return http
.csrf(csrf -> csrf.ignoringRequestMatchers(
"/mcp", "/mcp/messages", "/mcp/*/messages"))
.headers(headers -> headers.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31_536_000)))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/css/**", "/js/**", "/webjars/**",
"/mcp", "/mcp/sse", "/mcp/*/sse", "/mcp/messages", "/mcp/*/messages")
.permitAll()
.requestMatchers(HttpMethod.POST, "/login", "/logout").permitAll()
.requestMatchers(HttpMethod.POST,
"/probe",
"/vector-knowledge/search",
"/security-sql-scripts/explanation",
"/mcp-chatbot",
"/mcp-client-demo",
"/mcp-reasoning")
.authenticated()
.requestMatchers(HttpMethod.PUT, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.PATCH, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.POST, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(login -> login
.loginPage("/login")
.permitAll())
.logout(logout -> logout.logoutSuccessUrl("/login?logout"))
.build();
}
@Bean
UserDetailsService userDetailsService(
BackofficeProperties properties,
PasswordEncoder passwordEncoder
) {
var security = properties.security();
String encodedPassword = security.adminPasswordHash() == null || security.adminPasswordHash().isBlank()
? passwordEncoder.encode(security.adminPassword())
: security.adminPasswordHash();
List<UserDetails> users = new ArrayList<>();
users.add(User.withUsername(security.adminUser())
.password(encodedPassword)
.roles("ADMIN")
.build());
if (security.guestConfigured()) {
String encodedGuestPassword = security.guestPasswordHash() == null || security.guestPasswordHash().isBlank()
? passwordEncoder.encode(security.guestPassword())
: security.guestPasswordHash();
users.add(User.withUsername(security.guestUser())
.password(encodedGuestPassword)
.roles("VIEWER")
.build());
}
return new InMemoryUserDetailsManager(users);
}
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}

View File

@@ -1,8 +0,0 @@
package com.cloudhandson.vpdbackoffice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** Deployment-provided allow-list for bundled security SQL shown by the backoffice. */
@ConfigurationProperties(prefix = "backoffice.security-sql-scripts")
public record SecuritySqlScriptProperties(String scripts) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.audit;
public record AuditEvent(
String eventType,
Long keyId,
Long objectId,
String status,
Integer rowCount,
String errorCode,
String message
) {
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.effective;
import java.util.List;
public record EffectiveMatrixView(
List<UserEffectiveAccessView> users,
List<GroupEffectiveAccessView> groups,
List<RoleEffectiveImpactView> roles,
int permissionCount
) {
}

View File

@@ -1,15 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.effective;
import java.util.List;
public record GroupEffectiveAccessView(
long groupId,
String groupCode,
String groupName,
boolean active,
List<String> users,
List<String> roles,
int permissionCount,
List<String> objectNames
) {
}

View File

@@ -1,16 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.effective;
import java.util.List;
public record RoleEffectiveImpactView(
long roleId,
String roleName,
String maxSensitivityLevel,
List<String> directUsers,
List<String> groups,
List<String> inheritedUsers,
List<String> affectedUsers,
int permissionCount,
List<String> objectNames
) {
}

View File

@@ -1,18 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.effective;
import java.util.List;
public record UserEffectiveAccessView(
long userId,
String username,
String empNo,
String deptCode,
boolean active,
List<String> directRoles,
List<String> groups,
List<String> inheritedRoles,
List<String> effectiveRoles,
int permissionCount,
List<String> objectNames
) {
}

View File

@@ -1,14 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.group;
public record AppGroup(
long groupId,
String groupCode,
String groupName,
String description,
String activeYn
) {
public boolean active() {
return "Y".equalsIgnoreCase(activeYn);
}
}

View File

@@ -1,8 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.group;
public record GroupCreateCommand(
String groupCode,
String groupName,
String description
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.group;
public record GroupRoleView(
long groupId,
String groupCode,
String groupName,
long roleId,
String roleName
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.group;
public record GroupUserView(
long groupId,
String groupCode,
String groupName,
long userId,
String username
) {
}

View File

@@ -1,31 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
public record ColumnMaskingRule(
long columnId,
long objectId,
String owner,
String objectName,
String columnName,
long ruleId,
String ruleCode,
String ruleName,
String templateCode,
String ruleEnabledYn
) {
public String targetLabel() {
return owner + "." + objectName + "." + columnName;
}
public MaskingTemplate template() {
return MaskingTemplate.from(templateCode);
}
public String ruleLabel() {
return ruleName + " · " + template().label();
}
public boolean ruleEnabled() {
return "Y".equalsIgnoreCase(ruleEnabledYn);
}
}

View File

@@ -1,77 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
/**
* Read-only comparison between the configured masking metadata and the
* corresponding Oracle Data Redaction policy stored in the database.
*/
public record MaskingPolicyStatus(
String owner,
String objectName,
String policyName,
String enabled,
int configuredColumnCount,
int appliedColumnCount,
int mismatchedColumnCount,
int legacyVpdColumnPolicyCount
) {
public String targetLabel() {
return owner + "." + objectName;
}
public boolean policyEnabled() {
return "YES".equalsIgnoreCase(enabled);
}
/** A policy with no configured active column is correct only while disabled. */
public boolean inactiveAsExpected() {
return configuredColumnCount == 0 && !policyEnabled() && legacyVpdColumnPolicyCount == 0;
}
public boolean applied() {
return configuredColumnCount > 0
&& policyEnabled()
&& configuredColumnCount == appliedColumnCount
&& mismatchedColumnCount == 0
&& legacyVpdColumnPolicyCount == 0;
}
public String statusLabel() {
if (applied()) {
return "적용됨";
}
if (inactiveAsExpected()) {
return "미적용";
}
return "설정-DB 불일치";
}
public String badgeClass() {
if (applied()) {
return "text-bg-success";
}
if (inactiveAsExpected()) {
return "text-bg-secondary";
}
return "text-bg-danger";
}
public String detail() {
if (applied()) {
return "활성 규칙과 DB 정책 컬럼이 일치합니다.";
}
if (legacyVpdColumnPolicyCount > 0) {
return "기존 컬럼 NULL 정책(VPD CLS)이 활성입니다. ASO 설정과 별도로 값을 NULL 처리할 수 있습니다.";
}
if (inactiveAsExpected()) {
return "활성 컬럼 기본 규칙이 없어 DB 정책을 중지 상태로 보관합니다.";
}
if (configuredColumnCount > 0 && !policyEnabled()) {
return "활성 규칙이 있으나 DB 정책이 비활성입니다. 동기화가 필요합니다.";
}
if (configuredColumnCount == 0) {
return "활성 규칙이 없는데 DB 정책이 활성입니다. 동기화가 필요합니다.";
}
return "설정 컬럼과 DB Redaction 컬럼이 다릅니다. 동기화가 필요합니다.";
}
}

View File

@@ -1,23 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
public record MaskingRule(
long ruleId,
String ruleCode,
String ruleName,
String templateCode,
String description,
String enabledYn
) {
public boolean enabled() {
return "Y".equalsIgnoreCase(enabledYn);
}
public MaskingTemplate template() {
return MaskingTemplate.from(templateCode);
}
public String templateLabel() {
return template().label();
}
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
public record MaskingRuleCreateCommand(
String ruleCode,
String ruleName,
String templateCode,
String description
) {
}

View File

@@ -1,76 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
import java.util.Arrays;
/**
* Curated Data Redaction behaviours. A rule selects one template; operators
* never enter raw DBMS_REDACT expressions from the backoffice UI.
*/
public enum MaskingTemplate {
NULLIFY(
"NULLIFY",
"값 숨김 (NULL)",
"값을 NULL로 반환합니다. ASO/Data Redaction 컬럼 마스킹에 사용합니다.",
"DBMS_REDACT.NULLIFY",
"NULL"),
FULL(
"FULL",
"전체 마스킹",
"전체 값을 가립니다. Oracle 기본값은 문자형 공백, 숫자형 0입니다.",
"DBMS_REDACT.FULL",
"문자형은 공백 / 숫자형은 0"),
TEXT_PARTIAL(
"TEXT_PARTIAL",
"문자열 일부 마스킹",
"첫 글자만 남기고 나머지를 가리는 사전 정의 문자열 규칙입니다.",
"DBMS_REDACT.REGEXP",
"A******** (예시)"),
RRN_PARTIAL(
"RRN_PARTIAL",
"주민등록번호 부분 마스킹",
"앞 6자리만 표시하고 나머지는 가리는 사전 정의 식별번호 규칙입니다.",
"DBMS_REDACT.REGEXP",
"900101-******* (예시)");
private final String code;
private final String label;
private final String description;
private final String asoFunction;
private final String previewResult;
MaskingTemplate(String code, String label, String description, String asoFunction, String previewResult) {
this.code = code;
this.label = label;
this.description = description;
this.asoFunction = asoFunction;
this.previewResult = previewResult;
}
public String code() {
return code;
}
public String label() {
return label;
}
public String description() {
return description;
}
public String asoFunction() {
return asoFunction;
}
/** Human-readable result shown before an administrator assigns the rule. */
public String previewResult() {
return previewResult;
}
public static MaskingTemplate from(String code) {
return Arrays.stream(values())
.filter(value -> value.code.equalsIgnoreCase(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("지원하지 않는 마스킹 템플릿입니다: " + code));
}
}

View File

@@ -1,35 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.masking;
public record UserMaskingRule(
long userId,
String username,
long columnId,
String owner,
String objectName,
String columnName,
String ruleName,
String templateCode,
String decision,
String activeYn
) {
public boolean unmasked() {
return "UNMASK".equalsIgnoreCase(decision);
}
public boolean active() {
return "Y".equalsIgnoreCase(activeYn);
}
public String decisionLabel() {
return unmasked() ? "원문 표시 허용" : "기본값과 동일 · 마스킹";
}
public String targetLabel() {
return owner + "." + objectName + "." + columnName;
}
public String ruleLabel() {
return ruleName + " · " + MaskingTemplate.from(templateCode).label();
}
}

View File

@@ -1,13 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.mcp;
public record McpChatbotResult(
String contextPath,
String question,
String selectedTool,
String status,
String answer,
String routingReason,
String toolResultJson,
String toolsListJson
) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.mcp;
public record McpClientDemoResult(
String contextPath,
String messageUrl,
String selectedTool,
String initializeResponse,
String toolsListResponse,
String toolsCallResponse,
String status
) {
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.mcp;
public record McpReasoningCommand(
Long tokenKeyId,
String bearerToken,
int limit,
String question
) {
}

View File

@@ -1,13 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.mcp;
import com.cloudhandson.vpdbackoffice.domain.probe.ProbeResult;
public record McpReasoningResult(
String modelStatus,
String toolName,
String answer,
String prompt,
String evidenceJson,
ProbeResult probeResult
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.mcp;
public record McpToolView(
String name,
String description,
long objectId,
String displayName,
String ordsPath
) {
}

View File

@@ -1,141 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.operation;
import com.cloudhandson.vpdbackoffice.domain.masking.MaskingPolicyStatus;
import java.util.List;
/**
* Page-level health summary computed from the same DB-backed rows shown in
* operation-status.html. It intentionally does not hide the row-level evidence:
* the summary is only a triage layer for operators.
*/
public record OperationHealthSummary(
int protectedObjectCount,
int rowPolicyOkCount,
int rowPolicyWarnCount,
int rowPolicyErrorCount,
int missingHandlerCount,
int missingPolicyCount,
int invalidFunctionCount,
int unverifiedCount,
int maskingPolicyCount,
int maskingAppliedCount,
int maskingInactiveExpectedCount,
int maskingMismatchCount
) {
public static OperationHealthSummary from(
List<OperationStatusRow> rows,
List<MaskingPolicyStatus> maskingStatuses
) {
int rowPolicyOk = 0;
int rowPolicyWarn = 0;
int rowPolicyError = 0;
int missingHandler = 0;
int missingPolicy = 0;
int invalidFunction = 0;
int unverified = 0;
for (OperationStatusRow row : rows) {
switch (row.healthLevel()) {
case "OK" -> rowPolicyOk++;
case "ERROR" -> rowPolicyError++;
default -> rowPolicyWarn++;
}
if (row.handlerId() == null) {
missingHandler++;
}
if (row.policyNames() == null || row.policyNames().isBlank()) {
missingPolicy++;
}
if (row.functionStatus() != null && !"VALID".equalsIgnoreCase(row.functionStatus())) {
invalidFunction++;
}
if (row.lastProbeStatus() == null || row.lastProbeStatus().isBlank()) {
unverified++;
}
}
int maskingApplied = 0;
int maskingInactive = 0;
int maskingMismatch = 0;
for (MaskingPolicyStatus status : maskingStatuses) {
if (status.applied()) {
maskingApplied++;
} else if (status.inactiveAsExpected()) {
maskingInactive++;
} else {
maskingMismatch++;
}
}
return new OperationHealthSummary(
rows.size(),
rowPolicyOk,
rowPolicyWarn,
rowPolicyError,
missingHandler,
missingPolicy,
invalidFunction,
unverified,
maskingStatuses.size(),
maskingApplied,
maskingInactive,
maskingMismatch
);
}
public String overallLevel() {
if (rowPolicyErrorCount > 0 || invalidFunctionCount > 0 || maskingMismatchCount > 0) {
return "ERROR";
}
if (rowPolicyWarnCount > 0 || missingHandlerCount > 0 || missingPolicyCount > 0
|| unverifiedCount > 0) {
return "WARN";
}
return "OK";
}
public String overallLabel() {
return switch (overallLevel()) {
case "ERROR" -> "조치 필요";
case "WARN" -> "확인 필요";
default -> "정상";
};
}
public String overallBadgeClass() {
return switch (overallLevel()) {
case "ERROR" -> "text-bg-danger";
case "WARN" -> "text-bg-warning";
default -> "text-bg-success";
};
}
public String rowPolicySummary() {
return "정상 " + rowPolicyOkCount + " · 확인 " + rowPolicyWarnCount + " · 오류 " + rowPolicyErrorCount;
}
public String maskingSummary() {
return "적용 " + maskingAppliedCount + " · 미적용 정상 " + maskingInactiveExpectedCount
+ " · 불일치 " + maskingMismatchCount;
}
public String primaryAction() {
if (invalidFunctionCount > 0) {
return "컴파일 오류가 있는 VPD Filter를 먼저 확인하세요.";
}
if (maskingMismatchCount > 0) {
return "컬럼 마스킹 화면에서 DB ASO 정책 동기화를 확인하세요.";
}
if (missingPolicyCount > 0) {
return "보호 상태에서 행 접근 정책(VPD)을 적용하세요.";
}
if (missingHandlerCount > 0) {
return "조회 대상 또는 조회 연동에서 ORDS handler를 확인하세요.";
}
if (unverifiedCount > 0) {
return "접근 검증을 실행해 실제 결과를 확인하세요.";
}
return "현재 요약 기준으로 즉시 조치할 항목은 없습니다.";
}
}

View File

@@ -1,69 +0,0 @@
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)을 적용하세요.";
}
if (policyEnabled == null || !policyEnabled.toUpperCase().contains("YES")) {
return "행 접근 정책(VPD) 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

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.ords;
import jakarta.validation.constraints.NotBlank;
public record OrdsHandlerUpdateCommand(
long handlerId,
@NotBlank String source
) {
}

View File

@@ -1,26 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.ords;
import java.util.Locale;
public record OrdsHandlerView(
Long handlerId,
String schemaName,
String parsingSchema,
String moduleName,
String basePath,
String template,
String method,
String sourceType,
String source,
String parameters,
String packageSource
) {
public String fullPath() {
return "/ords/" + schemaName + "/" + basePath + template;
}
public boolean plsqlEditable() {
return sourceType != null && sourceType.toLowerCase(Locale.ROOT).contains("plsql");
}
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.ords;
public record OrdsObjectHandlerResult(
long objectId,
String ordsPath,
String moduleName,
String template
) {
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
public record AppRole(
long roleId,
String roleName,
String description,
String maxSensitivityLevel
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
public record PermissionRule(
long ruleId,
long permissionId,
String ruleColumn,
String ruleType,
String ruleValue
) {
}

View File

@@ -1,14 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
import java.util.List;
public record PermissionSet(
long permissionId,
long roleId,
long objectId,
String action,
String permissionEffect,
List<PermissionRule> rules,
List<String> visibleColumns
) {
}

View File

@@ -1,16 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Positive;
import java.util.List;
public record PermissionSetCommand(
@Positive long roleId,
@Positive long objectId,
@NotBlank String action,
String permissionEffect,
@NotEmpty List<RuleCommand> rules,
List<String> visibleColumns
) {
}

View File

@@ -1,84 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
public record PermissionView(
long permissionId,
long roleId,
String roleName,
long objectId,
String objectName,
String action,
String permissionEffect,
String rules,
String visibleColumns,
String filterPreview,
String nullPolicyPreview
) {
public String businessRuleSummary() {
if (rules == null || rules.isBlank()) {
return "-";
}
return java.util.Arrays.stream(rules.split(","))
.map(String::trim)
.filter(value -> !value.isBlank())
.map(PermissionView::businessRuleLabel)
.collect(java.util.stream.Collectors.joining(System.lineSeparator() + "AND "));
}
public String storedRuleSummary() {
return rules == null || rules.isBlank() ? "-" : rules;
}
public String vpdMappingSummary() {
return filterPreview == null || filterPreview.isBlank() ? "-" : filterPreview;
}
public String columnControlSummary() {
if (visibleColumns == null || visibleColumns.isBlank()) {
return "컬럼 원문/마스킹은 컬럼 마스킹에서 관리";
}
return "기존 권한별 표시 예외 값: " + visibleColumns
+ " · 신규 컬럼 제어는 컬럼 마스킹에서 관리";
}
private static String businessRuleLabel(String rawRule) {
String upper = rawRule.toUpperCase(java.util.Locale.ROOT);
if ("ALL".equals(upper)) {
return "전체 행";
}
if (upper.contains(" TOKEN_SUBJECT")) {
return "토큰으로 식별된 이해관계자 본인 행";
}
if (upper.contains(" OWN_CONTRACT")) {
return "담당 설계사 본인 계약";
}
if (upper.contains(" CHANNEL_CONTRACT")) {
return "토큰 사용자의 채널 계약";
}
if (upper.contains(" OWN_CUSTOMER")) {
return "담당 설계사 본인 계약에 연결된 고객/청구/외부보유";
}
if (upper.contains(" CHANNEL_CUSTOMER")) {
return "토큰 사용자 채널 계약에 연결된 고객/청구/외부보유";
}
if (upper.contains(" STATIC_SQL ")) {
return "정적 SQL 조건: " + rawRule.replaceFirst("(?i)^\\s*STATIC_SQL\\s+", "");
}
if (upper.startsWith("STATIC_SQL ")) {
return "정적 SQL 조건: " + rawRule.substring("STATIC_SQL ".length());
}
if ("MY_DEPT".equals(upper) || upper.contains(" MY_DEPT")) {
return "내 부서 행";
}
if ("MANAGED_TEAM".equals(upper) || upper.contains(" MANAGED_TEAM")) {
return "본인 및 직접 보고 팀원 행";
}
if ("SELF".equals(upper) || upper.contains(" SELF")) {
return "본인 직원 행";
}
if (upper.contains(" TAG ")) {
return "태그 조건: " + rawRule;
}
return rawRule;
}
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.permission;
import jakarta.validation.constraints.NotBlank;
public record RuleCommand(
String ruleColumn,
@NotBlank String ruleType,
String ruleValue
) {
}

View File

@@ -1,20 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
/**
* Durable, database-generated FGA evidence for a protected-object SELECT.
* SQL text and RLS information come from Oracle's audit trail, not from a
* re-evaluation of the VPD policy function.
*/
public record FgaExecutionEvidence(
String eventAt,
String dbUser,
String clientId,
String statementType,
String sqlText,
String rlsInfo
) {
public boolean hasRlsInfo() {
return rlsInfo != null && !rlsInfo.isBlank();
}
}

View File

@@ -1,19 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive;
public record ProbeCommand(
Long tokenKeyId,
@Positive long objectId,
@NotBlank String bearerToken,
@Min(1) @Max(500) int limit,
String requestBody
) {
public ProbeCommand(Long tokenKeyId, long objectId, String bearerToken, int limit) {
this(tokenKeyId, objectId, bearerToken, limit, null);
}
}

View File

@@ -1,288 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
import java.util.List;
import java.util.Map;
public record ProbeResult(
ProbeStatus status,
List<String> columns,
List<Map<String, Object>> rows,
int rowCount,
List<String> maskedColumns,
String errorCode,
String errorMessage,
String requestHeaders,
String requestPayload,
String responseHeaders,
String responseBody,
String vpdPredicate,
String effectiveSql,
SqlExecutionEvidence executionEvidence,
String executionEvidenceMessage,
List<SqlExecutionCandidate> executionCandidates,
FgaExecutionEvidence fgaExecutionEvidence,
String fgaExecutionEvidenceMessage
) {
public ProbeResult(
ProbeStatus status,
List<String> columns,
List<Map<String, Object>> rows,
int rowCount,
List<String> maskedColumns,
String errorCode,
String errorMessage,
String requestHeaders,
String requestPayload,
String responseHeaders,
String responseBody
) {
this(
status,
columns,
rows,
rowCount,
maskedColumns,
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody,
null,
null,
null,
null,
List.of(),
null,
null
);
}
public ProbeResult(
ProbeStatus status,
List<String> columns,
List<Map<String, Object>> rows,
int rowCount,
List<String> maskedColumns,
String errorCode,
String errorMessage,
String requestHeaders,
String requestPayload,
String responseHeaders,
String responseBody,
String vpdPredicate,
String effectiveSql
) {
this(
status,
columns,
rows,
rowCount,
maskedColumns,
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody,
vpdPredicate,
effectiveSql,
null,
null,
List.of(),
null,
null
);
}
public static ProbeResult blocked(ProbeStatus status, String errorCode, String errorMessage) {
return blocked(status, errorCode, errorMessage, null, null, null, null);
}
public static ProbeResult blocked(
ProbeStatus status,
String errorCode,
String errorMessage,
String requestHeaders,
String requestPayload,
String responseHeaders,
String responseBody
) {
return new ProbeResult(
status,
List.of(),
List.of(),
0,
List.of(),
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody
);
}
public boolean successLike() {
return status == ProbeStatus.SUCCESS || status == ProbeStatus.VPD_DENY_EMPTY_RESULT;
}
public boolean hasSqlTrace() {
return effectiveSql != null && !effectiveSql.isBlank();
}
public ProbeResult withSqlTrace(String predicate, String sql) {
return new ProbeResult(
status,
columns,
rows,
rowCount,
maskedColumns,
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody,
predicate,
sql,
executionEvidence,
executionEvidenceMessage,
executionCandidates,
fgaExecutionEvidence,
fgaExecutionEvidenceMessage
);
}
public boolean hasExecutionEvidence() {
return executionEvidence != null && executionEvidence.sqlId() != null
&& !executionEvidence.sqlId().isBlank();
}
public ProbeResult withExecutionEvidence(
SqlExecutionEvidence evidence,
String unavailableMessage
) {
return withExecutionEvidence(evidence, unavailableMessage, List.of());
}
public ProbeResult withExecutionEvidence(
SqlExecutionEvidence evidence,
String unavailableMessage,
List<SqlExecutionCandidate> candidates
) {
return new ProbeResult(
status,
columns,
rows,
rowCount,
maskedColumns,
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody,
vpdPredicate,
effectiveSql,
evidence,
unavailableMessage,
candidates == null ? List.of() : List.copyOf(candidates),
fgaExecutionEvidence,
fgaExecutionEvidenceMessage
);
}
public boolean hasExecutionCandidates() {
return executionCandidates != null && !executionCandidates.isEmpty();
}
public boolean hasFgaExecutionEvidence() {
return fgaExecutionEvidence != null && fgaExecutionEvidence.sqlText() != null
&& !fgaExecutionEvidence.sqlText().isBlank();
}
public ProbeResult withFgaExecutionEvidence(
FgaExecutionEvidence evidence,
String unavailableMessage
) {
return new ProbeResult(
status,
columns,
rows,
rowCount,
maskedColumns,
errorCode,
errorMessage,
requestHeaders,
requestPayload,
responseHeaders,
responseBody,
vpdPredicate,
effectiveSql,
executionEvidence,
executionEvidenceMessage,
executionCandidates,
evidence,
unavailableMessage
);
}
public String title() {
return switch (status) {
case SUCCESS -> "권한에 따라 데이터를 볼 수 있습니다.";
case VPD_DENY_EMPTY_RESULT -> "현재 권한으로 볼 수 있는 행이 없습니다.";
case TOKEN_NOT_FOUND -> "DB에 등록되지 않은 토큰입니다.";
case TOKEN_INACTIVE -> "만료되었거나 회수된 토큰입니다.";
case INVALID_TOKEN -> "입력한 토큰 정보가 일치하지 않습니다.";
case OBJECT_DISABLED -> "검증 대상이 비활성 상태입니다.";
case OBJECT_NOT_ACCESSIBLE -> "현재 권한으로 이 대상에 접근할 수 없습니다.";
case VPD_FILTER_ERROR -> "이 객체에 연결된 행 접근 Filter가 실행되지 않습니다.";
case ORDS_PATH_NOT_FOUND -> "검증 대상의 ORDS 경로를 찾지 못했습니다.";
case ORDS_NOT_CONFIGURED -> "ORDS 연결 주소가 아직 설정되지 않았습니다.";
case ORDS_UNAVAILABLE -> "ORDS 서버에 연결할 수 없습니다.";
case ORDS_TIMEOUT -> "ORDS 응답을 기다리다 시간이 초과되었습니다.";
case INVALID_ORDS_RESPONSE -> "ORDS 응답 형식을 해석할 수 없습니다.";
case UNKNOWN_ERROR -> "검증 중 예상하지 못한 문제가 발생했습니다.";
};
}
public String plainSummary() {
return switch (status) {
case SUCCESS -> "토큰의 사용자와 역할을 기준으로 행 접근 정책이 적용되었고, 허용된 데이터 " + rowCount
+ "개가 반환되었습니다.";
case VPD_DENY_EMPTY_RESULT -> "호출은 정상 처리됐지만 행 접근 정책이 현재 사용자에게 허용한 행은 0개입니다. 행 접근 규칙과 실제 데이터가 맞지 않으면 정상 결과이며 오류가 아닐 수 있습니다.";
case TOKEN_NOT_FOUND -> "입력한 원문과 일치하는 등록 기록이 현재 DB에 없습니다. 예전에 발급한 값이거나 다른 환경의 토큰일 수 있습니다.";
case TOKEN_INACTIVE -> "토큰은 DB에 있지만 만료되었거나 관리자가 회수해 더 이상 사용자 권한을 증명할 수 없습니다.";
case INVALID_TOKEN -> "화면에서 선택한 정보와 입력한 토큰 원문이 서로 다릅니다.";
case OBJECT_DISABLED -> "선택한 객체가 검증 대상으로 활성화되어 있지 않아 ORDS 호출을 시작하지 않았습니다.";
case OBJECT_NOT_ACCESSIBLE -> "토큰은 확인됐지만 ORDS 또는 DB가 이 객체에 대한 접근을 거부했습니다.";
case VPD_FILTER_ERROR -> "토큰과 사용자 권한은 확인됐지만, 대상 객체의 VPD 함수가 DB 오류를 내어 행 필터를 계산하지 못했습니다.";
case ORDS_PATH_NOT_FOUND -> "권한 판단 전 단계에서 실제 ORDS 주소와 등록된 객체 경로가 일치하지 않았습니다.";
case ORDS_NOT_CONFIGURED -> "백오피스가 호출할 ORDS 기준 주소가 없어 권한 검증을 시작하지 못했습니다.";
case ORDS_UNAVAILABLE -> "권한 판단 전 단계에서 ORDS 서버 또는 네트워크에 연결하지 못했습니다.";
case ORDS_TIMEOUT -> "ORDS가 제한 시간 안에 응답하지 않아 권한 결과를 확인하지 못했습니다.";
case INVALID_ORDS_RESPONSE -> "ORDS 호출은 끝났지만 rows/items 배열이 없는 응답이라 권한 결과로 표시하지 못했습니다.";
case UNKNOWN_ERROR -> "토큰, 권한, ORDS 중 어느 단계의 문제인지 기술 상세를 확인해야 합니다.";
};
}
public String nextAction() {
return switch (status) {
case SUCCESS -> "반환된 행과 ASO 마스킹 컬럼이 예상한 범위인지 확인하세요. 행 범위가 다르면 행 접근 규칙을, 컬럼 표시가 다르면 컬럼 마스킹을 조정한 뒤 다시 검증하세요.";
case VPD_DENY_EMPTY_RESULT -> "유효 권한 화면에서 사용자에게 직접 또는 그룹으로 상속된 역할과 행 규칙을 확인하세요.";
case TOKEN_NOT_FOUND -> "토큰 화면에서 현재 환경의 사용자에게 새 토큰을 발급하고, 한 번만 표시되는 원문을 복사해 다시 검증하세요.";
case TOKEN_INACTIVE -> "토큰 화면에서 활성 토큰을 새로 발급한 뒤 다시 검증하세요.";
case INVALID_TOKEN -> "복사한 원문이 맞는지 확인하고, 원문을 잃었다면 새 토큰을 발급하세요.";
case OBJECT_DISABLED -> "보호 객체를 활성화하고 권한을 등록한 뒤 다시 검증하세요.";
case OBJECT_NOT_ACCESSIBLE -> "유효 권한과 ORDS handler의 대상 객체가 같은지 확인하세요.";
case VPD_FILTER_ERROR -> "토큰이나 행 접근 규칙을 바꾸지 말고 DB 보호 연결에서 이 객체의 Filter를 확인하세요. 일반 권한 객체라면 표준 행 접근 Filter로 복구하세요.";
case ORDS_PATH_NOT_FOUND -> "보호 객체의 ORDS 경로와 실제 module/template 경로를 맞춘 뒤 다시 실행하세요.";
case ORDS_NOT_CONFIGURED -> "설정에서 ORDS 기준 주소를 등록한 뒤 백오피스를 재시작하세요.";
case ORDS_UNAVAILABLE, ORDS_TIMEOUT -> "행 접근 규칙을 바꾸지 말고 먼저 ORDS 실행 상태, 주소와 네트워크를 확인하세요.";
case INVALID_ORDS_RESPONSE -> "ORDS handler가 rows 또는 items 배열을 반환하는지 확인하세요.";
case UNKNOWN_ERROR -> "아래 기술 상세의 오류 코드와 응답을 확인한 뒤 해당 단계부터 점검하세요.";
};
}
}

View File

@@ -1,18 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
public enum ProbeStatus {
SUCCESS,
VPD_DENY_EMPTY_RESULT,
TOKEN_NOT_FOUND,
TOKEN_INACTIVE,
OBJECT_DISABLED,
INVALID_TOKEN,
OBJECT_NOT_ACCESSIBLE,
VPD_FILTER_ERROR,
ORDS_PATH_NOT_FOUND,
ORDS_NOT_CONFIGURED,
ORDS_UNAVAILABLE,
ORDS_TIMEOUT,
INVALID_ORDS_RESPONSE,
UNKNOWN_ERROR
}

View File

@@ -1,16 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
/**
* One of the most recently active database cursors shown verbatim during a
* probe. The match flag is calculated in Java, not by SQL text filtering in
* the database.
*/
public record SqlExecutionCandidate(
String sqlId,
int childNumber,
String parsingSchema,
String originalSql,
String lastActiveAt,
boolean matchesProtectedObject
) {
}

View File

@@ -1,23 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.probe;
/**
* Database shared-pool evidence for the statement most recently executed for
* a protected object. The SQL text is the statement submitted by ORDS before
* VPD rewrite; Oracle exposes the applied predicate through the cursor plan.
*/
public record SqlExecutionEvidence(
String sqlId,
int childNumber,
String originalSql,
String lastActiveAt,
long executions,
long rowsProcessed,
long elapsedMillis,
long bufferGets,
String predicatePlan
) {
public boolean hasPredicatePlan() {
return predicatePlan != null && !predicatePlan.isBlank();
}
}

View File

@@ -1,16 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.protectedobject;
public record DatabaseObjectOption(
String owner,
String objectName,
String objectType
) {
public String value() {
return owner + "." + objectName;
}
public String label() {
return owner + "." + objectName + " (" + objectType + ")";
}
}

View File

@@ -1,49 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.protectedobject;
import java.util.Locale;
public record ProtectedColumn(
long columnId,
long objectId,
String columnName,
String sensitiveYn,
Long visibleRoleId,
String sensitivityLevel,
String redactionMethod
) {
public boolean sensitive() {
return "Y".equalsIgnoreCase(sensitiveYn)
|| !"PUBLIC".equalsIgnoreCase(sensitivityLevel);
}
public String policyLabel() {
String level = sensitivityLevel == null || sensitivityLevel.isBlank() ? "PUBLIC" : sensitivityLevel;
String method = redactionMethod == null || redactionMethod.isBlank() ? "NONE" : redactionMethod;
return level + "/" + method;
}
public String sensitivityLabel() {
String level = sensitivityLevel == null || sensitivityLevel.isBlank() ? "PUBLIC" : sensitivityLevel;
return switch (level.toUpperCase(Locale.ROOT)) {
case "INTERNAL" -> "내부용";
case "CONFIDENTIAL" -> "기밀";
case "RESTRICTED" -> "제한";
default -> "기본 표시";
};
}
public String redactionLabel() {
String method = redactionMethod == null || redactionMethod.isBlank() ? "NONE" : redactionMethod;
return switch (method.toUpperCase(Locale.ROOT)) {
case "NULLIFY" -> "값 숨김(NULL)";
case "PARTIAL" -> "일부 숨김";
case "FULL" -> "전체 숨김";
default -> "마스킹 없음";
};
}
public String displayPolicyLabel() {
return sensitive() ? sensitivityLabel() + " · " + redactionLabel() : "기본 표시 · 마스킹 없음";
}
}

View File

@@ -1,29 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.protectedobject;
public record ProtectedObject(
long objectId,
String owner,
String objectName,
String ordsPath,
String enabledYn,
String description
) {
public ProtectedObject(long objectId, String owner, String objectName, String ordsPath, String enabledYn) {
this(objectId, owner, objectName, ordsPath, enabledYn, null);
}
public boolean enabled() {
return "Y".equalsIgnoreCase(enabledYn);
}
public String displayName() {
return owner + "." + objectName;
}
public String descriptionOrDefault() {
return description == null || description.isBlank()
? "등록된 DB 객체를 권한체계와 ORDS로 조회하는 대상"
: description;
}
}

View File

@@ -1,23 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.protectedobject;
import jakarta.validation.constraints.NotBlank;
public record ProtectedObjectCreateCommand(
@NotBlank String owner,
@NotBlank String objectName,
@NotBlank String ordsPath,
String columns,
String sensitiveColumns,
String description
) {
public ProtectedObjectCreateCommand(
String owner,
String objectName,
String ordsPath,
String columns,
String sensitiveColumns
) {
this(owner, objectName, ordsPath, columns, sensitiveColumns, null);
}
}

View File

@@ -1,14 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schema;
public record SchemaActionResult(
String objectName,
String action,
String status,
String message,
String sqlText
) {
public SchemaActionResult(String objectName, String action, String status, String message) {
this(objectName, action, status, message, null);
}
}

View File

@@ -1,28 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schema;
public record SchemaPreflightCheck(
String layer,
String itemName,
String objectType,
String status,
String detail,
String nextAction,
boolean sqlclRequired
) {
public boolean ok() {
return "OK".equalsIgnoreCase(status);
}
public boolean warning() {
return "WARN".equalsIgnoreCase(status);
}
public boolean missing() {
return "MISSING".equalsIgnoreCase(status);
}
public boolean error() {
return "ERROR".equalsIgnoreCase(status);
}
}

View File

@@ -1,38 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schema;
import java.util.List;
public record SchemaPreflightView(
String currentUser,
String recommendedOrdsSchema,
List<SchemaPreflightCheck> checks,
String appDdlPreview,
String sqlclScript
) {
public long okCount() {
return count("OK");
}
public long warnCount() {
return count("WARN");
}
public long missingCount() {
return count("MISSING");
}
public long errorCount() {
return count("ERROR");
}
public boolean hasActionNeeded() {
return warnCount() + missingCount() + errorCount() > 0;
}
private long count(String status) {
return checks.stream()
.filter(check -> status.equalsIgnoreCase(check.status()))
.count();
}
}

View File

@@ -1,4 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schemametadata;
public record SchemaAnnotation(String name, String value) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schemametadata;
import java.util.List;
public record SchemaMetadataColumn(
String columnName,
String dataType,
boolean nullable,
String comment,
List<SchemaAnnotation> annotations
) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.schemametadata;
import com.cloudhandson.vpdbackoffice.domain.structured.StructuredDataTable;
import java.util.List;
public record SchemaMetadataView(
StructuredDataTable table,
String tableComment,
List<SchemaAnnotation> tableAnnotations,
List<SchemaMetadataColumn> columns
) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.securityscript;
/** Curated, version-controlled database script displayed read-only in the backoffice. */
public record SecuritySqlScript(
String scriptId,
String category,
String fileName,
String title,
String description,
String source
) {
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.securityscript;
/** Explanation generated from one immutable, curated security SQL script. */
public record SecuritySqlScriptExplanation(
String status,
String modelName,
String answer,
String prompt,
SecuritySqlScript script
) {
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.securityscript;
/** Metadata for selecting a curated security SQL script without loading its source. */
public record SecuritySqlScriptSummary(
String scriptId,
String category,
String fileName,
String title,
String description
) {
}

View File

@@ -1,7 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.setting;
public record BackofficeSetting(
String settingKey,
String settingValue
) {
}

View File

@@ -1,18 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.stakeholder;
/**
* 업무 사용자 원장과 백오피스 권한 bridge를 결합한 Bearer Token 발급 대상이다.
*/
public record StakeholderTokenSubject(
String stakeholderUserId,
String username,
String role,
String channel,
String accessScope,
long appUserId
) {
public String displayLabel() {
return username + " / " + stakeholderUserId + " / " + role + " / " + channel;
}
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.structured;
import java.util.List;
import java.util.Map;
public record StructuredDataPreview(
StructuredDataTable table,
List<String> columns,
List<Map<String, Object>> rows,
int rowLimit
) {
}

View File

@@ -1,21 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.structured;
import java.util.List;
public record StructuredDataTable(
String key,
String tableName,
String objectType,
String businessName,
String description,
List<String> previewColumns
) {
public StructuredDataTable(String key, String tableName, String businessName, String description) {
this(key, tableName, "TABLE", businessName, description, List.of());
}
public boolean isTable() {
return "TABLE".equals(objectType);
}
}

View File

@@ -1,22 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.token;
import java.time.LocalDateTime;
public record BearerTokenRecord(
long keyId,
long userId,
String username,
String stakeholderUserId,
String stakeholderRole,
String stakeholderChannel,
String keyPrefix,
String keyHash,
LocalDateTime expiresAt,
LocalDateTime revokedAt,
String description
) {
public boolean active(LocalDateTime now) {
return revokedAt == null && expiresAt != null && expiresAt.isAfter(now);
}
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.token;
import java.time.OffsetDateTime;
public record IssuedToken(
long keyId,
String prefix,
String plainToken,
OffsetDateTime expiresAt
) {
}

View File

@@ -1,40 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.token;
import java.time.LocalDateTime;
import java.util.List;
public record TokenContextView(
long keyId,
long userId,
String username,
String stakeholderUserId,
String stakeholderRole,
String stakeholderChannel,
String keyPrefix,
LocalDateTime expiresAt,
LocalDateTime revokedAt,
String description,
boolean active,
List<String> directRoles,
List<String> groups,
List<String> inheritedRoles
) {
public String statusLabel() {
if (active) {
return "ACTIVE";
}
return revokedAt == null ? "EXPIRED" : "REVOKED";
}
public String maskedToken() {
if (keyPrefix == null || keyPrefix.isBlank()) {
return "****";
}
return keyPrefix + "****";
}
public String displayLabel() {
return "#" + keyId + " / " + username + " / " + statusLabel();
}
}

View File

@@ -1,13 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.token;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import java.time.OffsetDateTime;
public record TokenIssueCommand(
@Positive long userId,
@Future OffsetDateTime expiresAt,
@Size(max = 200) String description
) {
}

View File

@@ -1,15 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.user;
public record AppUser(
long userId,
String username,
String empNo,
String deptCode,
String canReadContents,
String activeYn
) {
public boolean active() {
return "Y".equalsIgnoreCase(activeYn);
}
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.user;
import jakarta.validation.constraints.NotBlank;
public record UserCreateCommand(
@NotBlank String username,
@NotBlank String empNo,
@NotBlank String deptCode
) {
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.user;
public record UserRoleView(
long userId,
String username,
long roleId,
String roleName
) {
}

View File

@@ -1,4 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
public record VectorChunk(int chunkNo, String text) {
}

View File

@@ -1,12 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
public record VectorIngestCommand(
String documentId,
String title,
String sourceUri,
String content,
String techTags,
int chunkSize,
String embeddingMode
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
public record VectorIngestResult(
String documentId,
int chunkCount,
int tagCount,
String embeddingMode,
String embeddingModel
) {
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
public record VectorKnowledgeSummary(
int documentCount,
int chunkCount,
int tagCount,
boolean vectorObjectRegistered,
String embeddingModel
) {
}

View File

@@ -1,9 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
public record VectorQueryEmbedding(
String query,
String embeddingMode,
String embeddingModel,
String requestBody
) {
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vector;
import com.cloudhandson.vpdbackoffice.domain.probe.ProbeResult;
public record VectorSearchResult(
String query,
String embeddingMode,
String embeddingModel,
ProbeResult probe
) {
}

View File

@@ -1,14 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdBulkApplyResult(
int total,
int created,
int skipped,
int failed
) {
public String summary() {
return "VPD bulk 적용 완료: 대상 " + total + "개, 등록 " + created
+ "개, 건너뜀 " + skipped + "개, 실패 " + failed + "";
}
}

View File

@@ -1,5 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
/** A saved VPD policy or filter description, addressed by a stable composite key. */
public record VpdDescriptionNote(String noteKey, String description) {
}

View File

@@ -1,23 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdFunctionOption(
String owner,
String packageName,
String functionName,
String objectType
) {
public String value() {
String packagePrefix = packageName == null || packageName.isBlank() ? "" : packageName + ".";
return owner + "." + packagePrefix + functionName;
}
public String label() {
return value() + " / " + objectType;
}
public boolean permissionSystemDefault() {
return "CB_AGENT_DOC_VPD_FILTER".equalsIgnoreCase(functionName)
|| "HMM_LEAVE_VPD_FILTER".equalsIgnoreCase(functionName);
}
}

View File

@@ -1,13 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdFunctionSource(
String owner,
String objectName,
String objectType,
String source
) {
public boolean found() {
return source != null && !source.isBlank();
}
}

View File

@@ -1,20 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
import java.util.List;
public record VpdObjectFilterDetail(
String objectOwner,
String objectName,
List<Row> rows
) {
public String objectDisplayName() {
return objectOwner + "." + objectName;
}
public record Row(
VpdPolicyView policy,
VpdFunctionSource source
) {
}
}

View File

@@ -1,15 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyCreateCommand(
String objectOwner,
String objectName,
String policyName,
String functionKey,
String functionOwner,
String functionName,
String statementTypes,
boolean enabled,
boolean updateCheck,
String filterPredicate
) {
}

View File

@@ -1,7 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyDetail(
VpdPolicyView policy,
String ddl
) {
}

View File

@@ -1,11 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyExplanation(
String status,
String modelName,
String answer,
String prompt,
VpdPolicyDetail detail,
VpdFunctionSource functionSource
) {
}

View File

@@ -1,33 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
import java.util.List;
public record VpdPolicyFormOptions(
List<String> policyNames,
List<String> schemaOwners,
List<String> owners,
List<VpdFunctionOption> functions,
List<VpdPolicyTemplateOption> policyTemplates,
List<String> statementTypes
) {
public String defaultPermissionFunctionKey() {
return functions.stream()
.filter(VpdFunctionOption::permissionSystemDefault)
.findFirst()
.map(VpdFunctionOption::value)
.orElse("");
}
public String defaultPermissionFunctionKey(String objectName) {
String preferredFunction = objectName != null
&& objectName.toUpperCase(java.util.Locale.ROOT).startsWith("HMM_LEAVE_")
? "HMM_LEAVE_VPD_FILTER"
: "CB_AGENT_DOC_VPD_FILTER";
return functions.stream()
.filter(function -> preferredFunction.equalsIgnoreCase(function.functionName()))
.findFirst()
.map(VpdFunctionOption::value)
.orElseGet(this::defaultPermissionFunctionKey);
}
}

View File

@@ -1,33 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyTemplateOption(
String policyName,
String functionOwner,
String packageName,
String functionName,
String statementTypes,
String enabled,
String checkOption
) {
public String functionKey() {
String packagePrefix = packageName == null || packageName.isBlank() ? "" : packageName + ".";
return functionOwner + "." + packagePrefix + functionName;
}
public String filterDisplayName() {
return functionKey();
}
public String label() {
return policyName + " / " + filterDisplayName() + " / " + statementTypes;
}
public boolean enabledValue() {
return "YES".equalsIgnoreCase(enabled);
}
public boolean updateCheckValue() {
return "YES".equalsIgnoreCase(checkOption);
}
}

View File

@@ -1,32 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyView(
String objectOwner,
String objectName,
String policyGroup,
String policyName,
String functionOwner,
String packageName,
String functionName,
String statementTypes,
String checkOption,
String enabled,
String staticPolicy,
String policyType,
String longPredicate
) {
public String objectDisplayName() {
return objectOwner + "." + objectName;
}
public String functionDisplayName() {
String packagePrefix = packageName == null || packageName.isBlank() ? "" : packageName + ".";
return functionOwner + "." + packagePrefix + functionName;
}
public boolean permissionSystemDefault() {
return "CB_AGENT_DOC_VPD_FILTER".equalsIgnoreCase(functionName)
|| "HMM_LEAVE_VPD_FILTER".equalsIgnoreCase(functionName);
}
}

View File

@@ -1,8 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdSchemaObjectOption(
String owner,
String objectName,
String objectType
) {
}

View File

@@ -1,26 +0,0 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdTargetView(
String owner,
String objectName,
String objectType,
String protectedYn,
String ordsPath,
String description,
int policyCount,
String policyNames,
String filterNames
) {
public String objectDisplayName() {
return owner + "." + objectName;
}
public boolean protectedObject() {
return "Y".equalsIgnoreCase(protectedYn);
}
public boolean vpdApplied() {
return policyCount > 0;
}
}

View File

@@ -1,10 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.audit.AuditEvent;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AuditMapper {
void insert(AuditEvent event);
}

View File

@@ -1,27 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.token.BearerTokenRecord;
import java.time.LocalDateTime;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface BearerTokenMapper {
List<BearerTokenRecord> findAll(@Param("includeInactive") int includeInactive);
BearerTokenRecord findById(@Param("keyId") long keyId);
BearerTokenRecord findByHash(@Param("keyHash") String keyHash);
long nextKeyId();
void insertToken(BearerTokenRecord token);
int revokeToken(
@Param("keyId") long keyId,
@Param("revokedAt") LocalDateTime revokedAt,
@Param("reason") String reason
);
}

View File

@@ -1,33 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.group.AppGroup;
import com.cloudhandson.vpdbackoffice.domain.group.GroupCreateCommand;
import com.cloudhandson.vpdbackoffice.domain.group.GroupRoleView;
import com.cloudhandson.vpdbackoffice.domain.group.GroupUserView;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface GroupMapper {
List<AppGroup> findAll();
List<GroupUserView> findGroupUsers();
List<GroupRoleView> findGroupRoles();
long nextGroupId();
void insertGroup(@Param("groupId") long groupId, @Param("command") GroupCreateCommand command);
int updateActive(@Param("groupId") long groupId, @Param("activeYn") String activeYn);
void insertGroupUser(@Param("groupId") long groupId, @Param("userId") long userId);
int deleteGroupUser(@Param("groupId") long groupId, @Param("userId") long userId);
void insertGroupRole(@Param("groupId") long groupId, @Param("roleId") long roleId);
int deleteGroupRole(@Param("groupId") long groupId, @Param("roleId") long roleId);
}

View File

@@ -1,56 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.masking.ColumnMaskingRule;
import com.cloudhandson.vpdbackoffice.domain.masking.MaskingRule;
import com.cloudhandson.vpdbackoffice.domain.masking.MaskingRuleCreateCommand;
import com.cloudhandson.vpdbackoffice.domain.masking.MaskingPolicyStatus;
import com.cloudhandson.vpdbackoffice.domain.masking.UserMaskingRule;
import com.cloudhandson.vpdbackoffice.service.MaskingPolicyTarget;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface MaskingRuleMapper {
List<MaskingRule> findAllRules();
List<MaskingRule> findEnabledRules();
MaskingRule findRuleById(@Param("ruleId") long ruleId);
MaskingRule findRuleByCode(@Param("ruleCode") String ruleCode);
long nextRuleId();
void insertRule(@Param("ruleId") long ruleId, @Param("command") MaskingRuleCreateCommand command);
int updateRuleActive(@Param("ruleId") long ruleId, @Param("enabledYn") String enabledYn);
List<ColumnMaskingRule> findColumnRules();
List<MaskingPolicyStatus> findPolicyStatuses(
@Param("owner") String owner,
@Param("policies") List<MaskingPolicyTarget> policies
);
ColumnMaskingRule findColumnRule(@Param("columnId") long columnId);
void upsertColumnRule(@Param("columnId") long columnId, @Param("ruleId") long ruleId);
int deleteColumnRule(@Param("columnId") long columnId);
int deleteUserRulesForColumn(@Param("columnId") long columnId);
List<UserMaskingRule> findUserRules();
UserMaskingRule findUserRule(@Param("userId") long userId, @Param("columnId") long columnId);
void upsertUserRule(
@Param("userId") long userId,
@Param("columnId") long columnId,
@Param("decision") String decision
);
int deleteUserRule(@Param("userId") long userId, @Param("columnId") long columnId);
}

View File

@@ -1,11 +0,0 @@
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

@@ -1,16 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.ords.OrdsHandlerView;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface OrdsMetadataMapper {
List<OrdsHandlerView> findHandlers();
OrdsHandlerView findHandler(@Param("handlerId") long handlerId);
String findHandlerPackageSource();
}

View File

@@ -1,70 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.permission.AppRole;
import com.cloudhandson.vpdbackoffice.domain.permission.PermissionRule;
import com.cloudhandson.vpdbackoffice.domain.permission.PermissionSet;
import com.cloudhandson.vpdbackoffice.domain.permission.PermissionView;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface PermissionMapper {
List<AppRole> findRoles();
AppRole findRole(@Param("roleId") long roleId);
long nextRoleId();
void insertRole(@Param("roleId") long roleId,
@Param("roleName") String roleName,
@Param("description") String description,
@Param("maxSensitivityLevel") String maxSensitivityLevel);
int updateRoleMaxSensitivity(@Param("roleId") long roleId,
@Param("maxSensitivityLevel") String maxSensitivityLevel);
int deleteRole(@Param("roleId") long roleId);
int countUserRolesByRoleId(@Param("roleId") long roleId);
int countGroupRolesByRoleId(@Param("roleId") long roleId);
int countPermissionsByRoleId(@Param("roleId") long roleId);
List<PermissionView> findPermissionViews();
PermissionSet findPermissionSet(@Param("roleId") long roleId, @Param("objectId") long objectId);
Long findPermissionId(@Param("roleId") long roleId, @Param("objectId") long objectId);
Long findObjectIdByPermissionId(@Param("permissionId") long permissionId);
int countPermissionsByObjectId(@Param("objectId") long objectId);
void insertPermission(@Param("permissionId") long permissionId,
@Param("roleId") long roleId,
@Param("objectId") long objectId,
@Param("action") String action,
@Param("permissionEffect") String permissionEffect);
void updatePermissionAction(@Param("permissionId") long permissionId, @Param("action") String action);
void updatePermissionEffect(@Param("permissionId") long permissionId,
@Param("permissionEffect") String permissionEffect);
void deleteRules(@Param("permissionId") long permissionId);
void insertRule(PermissionRule rule);
void deleteVisibleColumns(@Param("permissionId") long permissionId);
void insertVisibleColumn(@Param("permissionId") long permissionId, @Param("columnName") String columnName);
int deletePermission(@Param("permissionId") long permissionId);
long nextPermissionId();
long nextRuleId();
}

View File

@@ -1,59 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.protectedobject.DatabaseObjectOption;
import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedColumn;
import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedObjectCreateCommand;
import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedObject;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface ProtectedObjectMapper {
List<ProtectedObject> findEnabled();
List<ProtectedObject> findEnabledWithPermissions();
ProtectedObject findById(@Param("objectId") long objectId);
ProtectedObject findByOwnerAndName(@Param("owner") String owner, @Param("objectName") String objectName);
List<ProtectedColumn> findColumns(@Param("objectId") long objectId);
List<ProtectedColumn> findColumnsByObjectIds(@Param("objectIds") List<Long> objectIds);
ProtectedColumn findColumnById(@Param("columnId") long columnId);
ProtectedColumn findColumnByObjectAndName(@Param("objectId") long objectId,
@Param("columnName") String columnName);
List<DatabaseObjectOption> findDatabaseObjects();
List<String> findDatabaseColumns(@Param("owner") String owner, @Param("objectName") String objectName);
long nextObjectId();
long nextColumnId();
void insertObject(@Param("objectId") long objectId, @Param("command") ProtectedObjectCreateCommand command);
void insertColumn(@Param("columnId") long columnId,
@Param("objectId") long objectId,
@Param("columnName") String columnName,
@Param("sensitiveYn") String sensitiveYn,
@Param("sensitivityLevel") String sensitivityLevel,
@Param("redactionMethod") String redactionMethod);
int updateColumnPolicy(@Param("columnId") long columnId,
@Param("sensitivityLevel") String sensitivityLevel,
@Param("redactionMethod") String redactionMethod);
int updateOrdsPath(@Param("objectId") long objectId, @Param("ordsPath") String ordsPath);
int updateDescription(@Param("objectId") long objectId, @Param("description") String description);
int enableObject(@Param("objectId") long objectId);
int disableObject(@Param("objectId") long objectId);
}

View File

@@ -1,15 +0,0 @@
package com.cloudhandson.vpdbackoffice.mapper;
import com.cloudhandson.vpdbackoffice.domain.setting.BackofficeSetting;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface SettingMapper {
BackofficeSetting findByKey(@Param("settingKey") String settingKey);
void upsert(@Param("settingKey") String settingKey, @Param("settingValue") String settingValue);
void deleteByKey(@Param("settingKey") String settingKey);
}

Some files were not shown because too many files have changed in this diff Show More