package com.snp.batch.global.model; import jakarta.persistence.*; import lombok.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; /** * BYPASS API 설정 정보를 저장하는 엔티티 * 외부 API를 동적으로 프록시하기 위한 설정 메타데이터 * * JPA를 사용하므로 @PrePersist, @PreUpdate로 감사 필드 자동 설정 */ @Entity @Table(name = "bypass_api_config", uniqueConstraints = { @UniqueConstraint(name = "uk_bypass_config_domain_endpoint", columnNames = {"domain_name", "endpoint_name"}) }, indexes = { @Index(name = "idx_bypass_config_domain_name", columnList = "domain_name") } ) @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor public class BypassApiConfig { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 도메인명 (패키지명/URL 경로) * 예: "ship-info", "port-data" */ @Column(name = "domain_name", nullable = false, length = 50) private String domainName; /** * 엔드포인트명 (externalPath의 마지막 세그먼트에서 자동 추출) * 예: "CompliancesByImos", "CompanyCompliancesByImos" */ @Column(name = "endpoint_name", nullable = false, length = 100) private String endpointName; /** * 표시명 * 예: "선박 정보 API", "항만 데이터 API" */ @Column(name = "display_name", nullable = false, length = 100) private String displayName; /** * WebClient 빈 이름 * 예: "maritimeWebClient", "portWebClient" */ @Column(name = "webclient_bean", nullable = false, length = 100) private String webclientBean; /** * 외부 API 경로 * 예: "/api/v1/ships/{imoNumber}" */ @Column(name = "external_path", nullable = false, length = 500) private String externalPath; /** * HTTP 메서드 * 예: "GET", "POST" */ @Column(name = "http_method", nullable = false, length = 10) @Builder.Default private String httpMethod = "GET"; /** * 설명 */ @Column(name = "description", length = 1000) private String description; /** * 코드 생성 완료 여부 */ @Column(name = "generated", nullable = false) @Builder.Default private Boolean generated = false; /** * 코드 생성 일시 */ @Column(name = "generated_at") private LocalDateTime generatedAt; /** * 생성 일시 (감사 필드) */ @Column(name = "created_at", nullable = false, updatable = false) private LocalDateTime createdAt; /** * 수정 일시 (감사 필드) */ @Column(name = "updated_at", nullable = false) private LocalDateTime updatedAt; /** * API 파라미터 목록 */ @OneToMany(mappedBy = "config", cascade = CascadeType.ALL, orphanRemoval = true) @Builder.Default private List params = new ArrayList<>(); /** * 엔티티 저장 전 자동 호출 (INSERT 시) * endpointName이 null이면 externalPath에서 자동 추출 (마이그레이션 대응) */ @PrePersist protected void onCreate() { LocalDateTime now = LocalDateTime.now(); this.createdAt = now; this.updatedAt = now; if (this.endpointName == null || this.endpointName.isEmpty()) { this.endpointName = extractEndpointName(this.externalPath); } } /** * 엔티티 업데이트 전 자동 호출 (UPDATE 시) * endpointName이 null이면 externalPath에서 자동 추출 (마이그레이션 대응) */ private static String extractEndpointName(String externalPath) { if (externalPath == null || externalPath.isEmpty()) { return ""; } String[] segments = externalPath.split("/"); return segments[segments.length - 1]; } /** * 엔티티 업데이트 전 자동 호출 (UPDATE 시) */ @PreUpdate protected void onUpdate() { this.updatedAt = LocalDateTime.now(); if (this.endpointName == null || this.endpointName.isEmpty()) { this.endpointName = extractEndpointName(this.externalPath); } } }