Files
eapim-portal/CLAUDE.md
T
Rinjae(gf63) f7531412be
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled
- 약관 컨트롤러/서비스 테스트 추가: 동의서 노출 및 동작 방식 검증
- 사용자 등록 컨트롤러 테스트: 약관 노출 항목 설정 반영 확인
- 법인 가입/사용자 관리 관련 약관 동작 테스트 추가
2026-09-15 15:33:41 +09:00

25 KiB

CLAUDE.md

이 파일은 Claude Code(claude.ai/code)가 이 저장소의 코드를 작업할 때 참고하는 지침을 제공합니다.

프로젝트 개요

EAPIM Portal은 제주은행을 위한 엔터프라이즈 API 포털 관리 시스템입니다. API 서비스 관리, 사용자 등록, API 키 발급, 문서화, 테스트 기능을 제공하는 웹 기반 플랫폼입니다.

기술 스택:

  • Spring Boot 2.7.18 with Spring MVC and Thymeleaf
  • Java 8 (sourceCompatibility/targetCompatibility: 1.8)
  • Gradle 8.7 빌드 시스템
  • Oracle 19c 데이터베이스 (JNDI를 통한 이중 데이터소스)
  • Spring Security (커스텀 인증)
  • JPA/Hibernate 5.6.15 with Envers (감사 추적)
  • MapStruct (DTO 매핑), Lombok (보일러플레이트 제거)
  • SASS/SCSS (CSS 전처리기) - 스타일 수정 시 반드시 SASS 파일 수정

CSS/SASS 가이드:

  • CSS 파일(src/main/resources/static/css/main.css)은 SASS에서 컴파일된 결과물
  • 스타일 수정 시 반드시 SASS 파일(src/main/resources/static/sass/)을 수정해야 함
  • CSS 파일 직접 수정 금지 - SASS 파일 수정 후 컴파일 필요
  • SASS 컴파일: sass src/main/resources/static/sass/main.scss src/main/resources/static/css/main.css

Git 브랜치 전략

저장소 정보:

  • origin: ssh://git@172.30.1.50:2222/djb-eapim/eapim-portal.git (Gitea, 사내망)
  • 이 저장소가 유일한 remote다. Jenkins 파이프라인도 같은 주소를 본다.

브랜치:

  • master: 기본 개발 브랜치이자 배포 기준 브랜치

    • 일상적인 개발 작업(기능 개발, 버그 수정)을 여기서 직접 수행한다
    • Jenkins 4개 파이프라인(Jenkinsfile.*)이 모두 origin/master 를 체크아웃한다
    • Jenkinsfile.security 는 pollSCM 으로 master 변경을 감지해 자동 실행된다
  • feats/*, design*, develop: 과거 작업 잔여 브랜치

    • 현재 활성 개발에 사용하지 않는다. 참고용으로만 남아 있다

과거 문서에 있던 jenkins_with_weblogic 브랜치는 존재하지 않는다. Jenkins/WebLogic 설정은 master 의 Jenkinsfile.deploy 에 통합되어 있다.

작업 흐름:

# master 에서 바로 작업
git checkout master
git pull origin master

# 커밋 후 푸시 → Jenkins security 파이프라인이 자동 트리거됨
git add .
git commit -m "기능 설명"
git push origin master

빌드 명령어

애플리케이션 실행

  • Linux 개발 환경에서는 gradlew 대신 설치된 gradle(8.7)을 직접 쓴다. Jenkins 노드도 /apps/opts/gradle-8.7gradle 을 쓴다.
  • Windows/Eclipse 환경 기동 절차는 BOOTRUN_SETUP_GUIDE.md 참고 (거기서는 gradlew.bat bootRun 사용).
  • .envrc(direnv)는 없다. JAVA_HOME(JDK 8)/GRADLE_HOME 은 셸에서 직접 맞춰야 한다.
# bootRun 기본 프로파일은 build.gradle 의 bootProfile 기본값(local_rinjaemac)
gradle bootRun

# 다른 프로파일로 기동 (--args 가 아니라 -PbootProfile)
gradle bootRun -PbootProfile=dev

bootRun 의 프로파일은 -PbootProfile 로 넘긴다. -Pprofileext.profile='local' 이 이미 점유하고 있어 무시된다(build.gradle 의 주석 참고). Jenkins 빌드에서 쓰는 -Pprofile=weblogic 은 스프링 프로파일이 아니라 빌드용 플래그다.

빌드

# Spring Boot 실행 가능 WAR 빌드
gradle bootWar
# 출력: build/libs/eapim-portal-boot.war

# 애플리케이션 서버용 표준 WAR 빌드 (JEUS/WebLogic)
gradle war
# 출력: build/libs/eapim-portal.war

# 클린 후 빌드
gradle clean build

# SBOM(xlsx) 생성 - Jenkins 빌드 파이프라인에서 사용
gradle sbomXlsx

테스트

# 모든 테스트 실행
gradle test

# 로그 상세 출력
gradle test --info

# 특정 테스트 클래스 실행
gradle test --tests "com.eactive.apim.portal.apps.user.AccountControllerTest"

# 패턴에 매칭되는 테스트 실행
gradle test --tests "*Controller*"

커버리지는 측정되지 않는다. JaCoCo 플러그인이 build.gradle 에 없고 sonar-project.properties 에도 sonar.coverage.jacoco.xmlReportPaths 가 없다. 그래서 SonarQube 의 Coverage 가 항상 0% 로 뜨고 Quality Gate 가 ERROR 가 된다 (Sonar 의 Zero Coverage Sensor 가 리포트 없는 라인을 전부 0 으로 채운다).

CSS/SASS 빌드

npm run sass:build      # main.css (expanded)
npm run build           # main.css + main.min.css
npm run sass:watch      # 변경 감시
./sass-build.sh         # sass CLI 직접 호출 (npm 없이)

개발

# 현재 프로파일 확인 (-Pprofile 로 넘긴 값)
gradle printProfile

# 소스 세트 설정 확인
gradle printSourceSets

Docker

build_docker.sh없다. Dockerfile 만 있으므로 직접 빌드한다.

gradle bootWar
docker build -t eapim-portal:latest .

아키텍처

멀티 모듈 구조

이 프로젝트는 settings.gradle 의 멀티 프로젝트 구성으로 2개의 형제 디렉터리 모듈에 의존합니다:

  1. elink-online-core-jpa (../eapim-online/elink-online-core-jpa)

    • Gateway 데이터 모델 및 JPA 엔티티
    • API 명세 엔티티 및 리포지토리 제공
    • 패키지: com.eactive.eai.data.entity.onl.*
  2. elink-portal-common (../elink-portal-common)

    • 공유 포털 유틸리티 및 공통 컴포넌트
    • 기본 리포지토리 구현, QueryDSL 지원
    • 공통 예외 핸들러 및 보안 유틸리티

두 모듈은 Jenkins 파이프라인의 Checkout dependencies 스테이지가 같은 Gitea 서버에서 자동으로 clone/reset 한다. 로컬에서도 ../eapim-online/elink-online-core-jpa../elink-portal-common 이 없으면 컴파일 자체가 되지 않는다.

kjb-safedb (SafeDB 암호화 라이브러리)는 현재 빌드에서 빠져 있다. build.gradleimplementation project(':kjb-safedb') 가 주석 처리되어 있고 settings.gradle 에도 등록되어 있지 않으며 ../kjb-safedb 디렉터리도 없다. 다시 붙일 때는 세 곳을 모두 되살려야 한다.

패키지 구조

코드는 기술 계층이 아닌 기능 모듈(수직 분할) 방식으로 구성됩니다:

com.eactive.apim/
├── portal/
│   ├── PortalApplication.java
│   ├── apps/                      # 기능 모듈
│   │   ├── HealthCheckController.java
│   │   ├── ReadinessController.java
│   │   ├── agreements/            # API 약관
│   │   ├── apis/                  # API 카탈로그 & 문서
│   │   ├── apiservice/            # API 서비스 그룹핑
│   │   ├── app/                   # API 키 관리
│   │   ├── approval/              # 승인 워크플로우
│   │   ├── auth/                  # 인증
│   │   ├── community/             # FAQ, 공지사항, Q&A, 제휴문의
│   │   ├── dashboard/             # 대시보드
│   │   ├── file/                  # 파일 업로드/다운로드
│   │   ├── login/                 # 로그인/로그아웃
│   │   ├── main/                  # 메인 화면
│   │   ├── sample/                # 샘플 코드 생성
│   │   ├── session/               # 세션 관리 (filter/entity/repository 포함)
│   │   ├── statistics/            # API 통계
│   │   └── user/                  # 사용자 관리
│   ├── common/                    # 공통 관심사
│   ├── config/                    # Spring 설정
│   ├── custom/                    # 사이트별 커스터마이징 설정
│   ├── djb/                       # 은행 특화 기능
│   │   ├── apistatus/  community/  footer/  guide/  menu/  notitest/
│   ├── spring/                    # DatabaseSessionVerifier 등
│   └── tools/                     # HibernateSqlGenerator, JpaErrorLoggingAspect
└── gateway/                       # Gateway DB 직접 접근 (portal 의 하위가 아님)

apps/proxy/ 패키지는 더 이상 없다. 과거 문서의 Forward Proxy 모듈 설명은 무효다.

각 기능 모듈은 일반적으로 다음을 포함합니다:

  • controller/ - Spring MVC 컨트롤러 (@Controller)
  • service/ - 비즈니스 로직 (@Service, @Transactional)
  • repository/ - Spring Data JPA 리포지토리
  • dto/ - 데이터 전송 객체 (Lombok @Data)
  • mapper/ - MapStruct 인터페이스 (entity ↔ DTO 변환)

이중 데이터베이스 아키텍처

애플리케이션은 두 개의 Oracle 데이터베이스를 사용합니다:

  1. EMS Database (Portal/Admin)

    • JNDI: jdbc/dsOBP_EMS
    • Schema: EMSAPP
    • Entities: com.eactive.apim.portal.apps.*
    • 목적: 포털 사용자, 조직, API 키, 승인
  2. Gateway Database (API Specs)

    • JNDI: jdbc/dsOBP_AGW
    • Schema: AGWAPP
    • Entities: com.eactive.eai.data.entity.onl.*
    • 목적: API 명세, 서비스, 메시지

두 데이터소스 모두 dev 프로파일에서도 JNDI 로 연결한다(application-dev.yml, application-stage.yml). 직접 JDBC URL 을 쓰는 프로파일은 없다.

설정: config/PortalDatasourceConfiguration.java

  • 각 데이터베이스별 별도 EntityManager
  • JTA/XA 미사용. EntityManagerFactory 별 로컬 트랜잭션 (config/PortalConfigTransaction.java)
    • transactionManager (@Primary) → EMS
    • gatewayTransactionManager → Gateway

설정 프로파일

환경별 설정 파일: src/main/resources/application-{profile}.yml

저장소에 실제로 있는 프로파일은 4개다:

  • dev: 개발 환경 (DevTools 활성화, SQL 로깅)
  • stage: 스테이징 환경 (JNDI 데이터소스, proxy to inter-dapiwas01)
  • prod: 운영 환경 (JNDI 데이터소스, proxy to inter-apiwas00, 캐싱 활성화)
  • local_gf63: 개인 로컬 개발 환경

bootRun 의 기본값은 build.gradle 에서 local_rinjaemac 으로 잡혀 있지만 application-local_rinjaemac.yml 은 저장소에 없다. 기본값 그대로 gradle bootRun 을 하면 해당 프로파일 설정 없이 뜨므로, 로컬 기동 시에는 -PbootProfile=dev 처럼 명시하는 편이 안전하다.

주요 설정 (application.yml):

  • 세션 타임아웃: 10분 (server.servlet.session.timeout: 10m, WebLogic 은 weblogic.xmltimeout-secs 600)
  • 세션 쿠키명: JSESSIONID_PORTAL
  • 파일 업로드 최대: 10MB (portal.file.max-size)
  • 비밀번호 만료: 90일 (portal.password-expiration-days)
  • 인증 토큰 TTL: 5분 (portal.auth-ttl: 300), 재발송 제한 30초
  • 사용자 승인 필수: portal.user-approval: true
  • 내부 사용자 판별 도메인: portal.internal-user.email-domains

주요 기능 및 비즈니스 로직

사용자 관리 (apps/user/)

두 가지 사용자 유형:

  1. 내부 사용자 (Staff): 포털 관리자 및 운영자
  2. 기업 사용자 (Enterprise): 외부 API 소비자

사용자 라이프사이클:

  • 가입 → 이메일 인증 → 관리자 승인 → 활성화
  • 비밀번호 정책 적용 (90일 만료, 복잡도 규칙)
  • 로그인 실패 시 계정 잠금
  • 휴면 계정 관리

API 키 관리 (apps/app/)

API 키는 승인 워크플로우와 함께 관리됩니다:

  • 기업 관리자가 AppRequestController를 통해 키 요청
  • 관리자가 ApprovalController를 통해 승인/반려
  • 키는 개발/운영 환경 지원
  • 키는 eLink Gateway ClientID/ClientSecret과 연결

승인 워크플로우 (apps/approval/)

다음 항목에 대한 범용 승인 시스템:

  • 사용자 등록 승인
  • API 키 생성/수정
  • 제휴 신청

엔티티: Approval, Approver, ApprovalStatus (WAITING, APPROVED, REJECTED)

API 테스트 (apps/apis/)

  • API 테스터: apps/apis/filter/ApiTesterFilter.java
  • Testbed 스펙 제공: apps/apis/controller/TestbedSpecController.java
  • 샘플 코드 템플릿: application.ymlsample-code-path: classpath:/templates/sample_code

apps/sample/ 은 샘플 코드 생성기가 아니라 Thymeleaf/Security 데모 컨트롤러 (ThymeleafDemoController, SecurityThymeleafDemoController 등) 모음이다.

감사 추적 (Hibernate Envers)

모든 엔티티는 자동 감사를 위해 AbstractAuditingEntity를 확장합니다:

  • createdBy, createdDate
  • lastModifiedBy, lastModifiedDate
  • @Audited 어노테이션으로 변경 이력 관리
  • Spring Data Envers를 통한 이력 조회

공통 개발 패턴

새 기능 모듈 추가하기

  1. apps/ 하위에 패키지 생성 (예: apps/newfeature/)
  2. controller/, service/, repository/, dto/, mapper/로 구조화
  3. repository/entity/에 JPA 엔티티 생성 (AbstractAuditingEntity 확장)
  4. dto/에 Lombok @Data를 사용한 DTO 생성
  5. mapper/에 MapStruct 매퍼 인터페이스 생성
  6. @Service@Transactional을 사용한 서비스 계층 구현
  7. @Controller@RequestMapping을 사용한 컨트롤러 생성
  8. src/main/resources/templates/views/newfeature/에 Thymeleaf 템플릿 추가
  9. application.ymlpages 섹션에 라우트 설정 (또는 @GetMapping/@PostMapping으로 직접 매핑)

메뉴/네비게이션 항목 추가하기

중요: 메뉴 정의가 두 곳으로 분리되어 있다. yml 한 곳만 고치면 헤더 드롭다운에 안 보이고, 헤더만 고치면 브레드크럼이 비어 보인다. 메뉴 추가/이름 변경/순서 변경 시 반드시 두 파일을 같이 수정한다.

  1. application.ymlpage: 트리 (브레드크럼·페이지 메타용)

    • PageService가 URL → breadcrumb 매핑에 사용
    • 부모 메뉴(service, apis, community 등) 아래 children:에 새 키를 추가
    page:
      home:
        children:
          service:
            children:
              oauth2_guide:
                name: "OAuth2 인증가이드"
                path: "/service/oauth2-guide"
    
  2. templates/views/fragment/djbank/header_container.html (상단 글로벌 네비)

    • <nav class="header-center"><ul class="nav-menu"> 블록에 정적 <li>로 하드코딩되어 있다 — yml 트리를 iterate 하지 않음
    • 부모 메뉴의 <ul class="sub-menu"><li><a th:href="@{/...}">메뉴명</a></li> 직접 추가
  3. 라우트도 같이 등록 (application.ymlportal.pages 매핑 섹션, 또는 @GetMapping)

    portal:
      pages:
        - path-pattern: /service/oauth2-guide
          method: GET
          view-name: apps/service/oauth2-guide
    
  4. 검증: 변경 후 (a) 헤더 드롭다운에 항목이 보이는지, (b) 새 페이지 진입 시 브레드크럼에 메뉴명이 보이는지 둘 다 확인.

  5. 재시작: application.yml 변경은 PortalPageHandlerMapper@PostConstruct에서 한 번만 등록하므로 자동 라이브 리로드 안 됨 — 수동 재시작 필요. HTML/CSS만 라이브 반영됨.

MapStruct DTO 매핑

타입 안전한 DTO 변환을 위해 MapStruct 사용:

@Mapper(componentModel = "spring")
public interface UserMapper {
    PortalUserDto toDto(PortalUser entity);
    PortalUser toEntity(PortalUserDto dto);
    List<PortalUserDto> toDtoList(List<PortalUser> entities);
}

생성된 구현체는 build/generated/sources/annotationProcessor/java/main/에 위치

보안 및 인증

보안 설정: config/PortalConfigSecurity.java

  • 커스텀 인증 관리자: PortalAuthenticationManager
  • changeSessionId()를 통한 세션 고정 공격 방어
  • CSRF: HttpSessionCsrfTokenRepository(세션 저장), 헤더명 X-XSRF-TOKEN 고정 — 쿠키 기반(CookieCsrfTokenRepository)이 아니다. 토큰 수명은 세션 타임아웃과 같다
  • XSS: Naver Lucy XssEscapeServletFilter
  • 비밀번호 전송암호화(RSA-OAEP + AES-GCM): common/security/passwordcrypto/ — 필터 순서상 MultipartFilter 이후, Lucy XSS 필터 이전에 복호화된다

역할 계층 (정의: src/main/resources/roles.yml, 부팅 시 PTL_ROLE / PTL_ROLE_AUTHORITY 에 미러 적재):

ROLE_USER (개인사용자)   → [ROLE_INQUIRY, ROLE_ACCOUNT]

ROLE_CORP_USER (법인사용자) → [ROLE_API_KEY_REQUEST, ROLE_API_KEY_REQUEST_VIEW,
                              ROLE_INQUIRY, ROLE_APP, ROLE_ACCOUNT]

ROLE_CORP_MANAGER (법인관리자) → [ROLE_API_KEY_REQUEST, ROLE_API_KEY_REQUEST_VIEW,
                                 ROLE_WEBHOOK, ROLE_INQUIRY, ROLE_APP, ROLE_ACCOUNT,
                                 ROLE_CORP_API, ROLE_DASHBOARD, ROLE_USER_MANAGER]

데이터베이스 쿼리

Spring Data JPA 리포지토리 메서드 사용 권장:

public interface PortalUserRepository extends JpaRepository<PortalUser, Long> {
    Optional<PortalUser> findByEmail(String email);

    @Query("SELECT u FROM PortalUser u WHERE u.status = :status")
    List<PortalUser> findByStatus(@Param("status") UserStatus status);
}

복잡한 쿼리는 QueryDSL 사용:

QPortalUser user = QPortalUser.portalUser;
return queryFactory.selectFrom(user)
    .where(user.email.eq(email)
        .and(user.status.eq(UserStatus.ACTIVE)))
    .fetchOne();

트랜잭션 관리

적절한 propagation과 함께 @Transactional 사용:

  • 기본값: REQUIRED (기존 트랜잭션에 참여하거나 새로 생성)
  • 읽기 전용 작업: 최적화를 위해 @Transactional(readOnly = true)
  • 다중 데이터베이스: 분산 트랜잭션(JTA/XA) 없음. EMS·Gateway 각각 독립 로컬 트랜잭션이다.
    • 무지정 @Transactional = EMS(transactionManager)
    • Gateway 엔티티(com.eactive.apim.gateway.*, com.eactive.eai.data.entity.onl.*)를 다루는 서비스는 @Transactional("gatewayTransactionManager") 를 명시한다. 안 하면 게이트웨이 EntityManager 가 리포지토리 호출 단위로 닫혀 지연 로딩에서 LazyInitializationException 이 난다 (예: ApiServiceServiceApiGroup.apiGroupApiList).
    • 두 DB 를 한 원자 단위로 묶어야 하는 작업은 만들지 않는다. 현재 Gateway 는 조회 전용이다.

에러 처리

common/exception/의 글로벌 예외 처리:

  • @ControllerAdvice가 적용된 GlobalExceptionHandler
  • 커스텀 예외는 RuntimeException 확장
  • Thymeleaf 에러 뷰 또는 AJAX 요청에는 JSON 반환

로깅

로깅은 application.ymllogging.file.path 가 아니라 logback 설정으로 제어한다.

  • 설정 파일: src/main/resources/logback-spring.xml (그 외 logback-debug.xml, logback-local_gf63.xml)
  • 로그 디렉터리: portal.logging.log-path yml 프로퍼티 + 인스턴스명
    <springProperty scope="context" name="profileLogPath" source="portal.logging.log-path"/>
    <property name="LOG_PATH" value="${profileLogPath}/${inst.Name:-devSvr00}"/>
    
  • application.yml 기본값: portal.logging.log-path: /logs/prod/eapim
  • 산출 파일: ${LOG_PATH}/portal.log, ${LOG_PATH}/hibernate.log 등 (backup/ 에 일자 롤링)

Lombok의 @Slf4j와 함께 SLF4J 사용:

@Slf4j
@Service
public class UserService {
    public void someMethod() {
        log.debug("디버그 메시지");
        log.info("정보 메시지");
        log.error("에러 메시지", exception);
    }
}

테스트 가이드

테스트 구조

src/test/java/com/eactive/apim/portal/의 테스트:

  • BaseWebTest - Spring Boot 테스트 컨텍스트를 가진 기본 클래스
  • 컨트롤러 테스트는 BaseWebTest 확장
  • 통합 테스트는 @SpringBootTest 사용
  • 독립적인 컨트롤러 테스트는 @WebMvcTest 사용

일반적인 테스트 패턴

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest extends BaseWebTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void testUserRegistration() throws Exception {
        mockMvc.perform(post("/user/register")
                .param("email", "test@example.com")
                .with(csrf()))
            .andExpect(status().isOk())
            .andExpect(view().name("user/register-success"));
    }
}

SafeDB

SafeDB 모듈이 현재 빌드에서 빠져 있으므로(위 "멀티 모듈 구조" 참고) 테스트에서 별도로 켜고 끌 것이 없다. -Dsafedb= 옵션은 더 이상 동작하지 않는다.

중요 사항

한글 지원

이 포털은 한글을 광범위하게 사용합니다:

  • Thymeleaf 템플릿은 한글 레이블 사용
  • 데이터베이스는 한글 데이터 포함 (UTF-8)
  • 한글 메시지 프로퍼티 (messages_ko.properties)
  • 한글 사용자 가이드 (개발자포탈.md)

비밀번호 정책

PortalUserValidator에서 적용:

  • 최소 8자
  • 대문자, 소문자, 숫자, 특수문자 포함 필수
  • 연속된 문자 사용 불가
  • 최근 3개 비밀번호 재사용 불가
  • 90일 후 만료

세션 관리

  • 사용자당 단일 세션 강제
  • 세션 타임아웃: 10분 (쿠키명 JSESSIONID_PORTAL)
  • 로그인 시 changeSessionId() 로 세션 고정 공격 방어
  • 세션 상태는 DB 에 보관하며 apps/session/ (filter/entity/repository) 과 spring/DatabaseSessionVerifier.java 가 담당한다. Redis 는 쓰지 않는다.

파일 업로드 제한

application.ymlportal.file 로 제어하고 config/PortalProperties.java 가 바인딩한다:

portal:
  file:
    max-size: 10MB
    allowed-extensions: pdf,doc,docx,xls,xlsx,ppt,pptx,hwp,gif,jpg,jpeg,png
  • 적용 지점: config/MultipartConfig.java (setMaxUploadSize / setMaxUploadSizePerFile)
  • 초과 시 메시지: common/exception/PortalGlobalExceptionHandler.java
  • PortalProperties 의 코드 기본값은 8MB 이지만 yml 이 10MB 로 덮어쓴다
  • 다운로드는 apps/file/controller/FileDownloadController.java 하나뿐이다

배포

애플리케이션 서버 지원

WAR 파일 호환 서버:

  • WebLogic (src/main/resources/weblogic.xml) — 현재 실제 배포 대상
  • JEUS (src/main/resources/jeus-web-dd.xml)
  • Tomcat (Spring Boot 내장)

실제 배포는 Jenkinsfile.deploy 가 수행한다: djb-vm 노드에서 WAR 를 빌드해 stash 하고, weblogic 라벨 노드에서 WebLogic 정지 → WAR 교체 → 기동 → readiness 확인 순으로 진행한다.

Jenkins 파이프라인

저장소 루트에 4개의 Jenkinsfile 이 있고 모두 origin/master 를 대상으로 한다:

파일 용도
Jenkinsfile.security OWASP Dependency-Check(SCA) + SonarQube(SAST). pollSCM 자동 트리거
Jenkinsfile.sonar SonarQube 정적 분석 전용
Jenkinsfile.test-build 테스트 + WAR 빌드 + SBOM
Jenkinsfile.deploy 빌드 후 WebLogic 배포

빌드는 JDK 8(/apps/opts/jdk8), SonarScanner/Dependency-Check 실행은 JDK 17 (/apps/opts/jdk17)로 분리되어 있다. 스캐너 설정은 sonar-project.propertiesci/ 디렉터리(sonar-classpath.gradle, dependency-check-classpath.gradle, dependency-check-suppressions.xml)에 있다.

알려진 CI 이슈 두 가지:

  • Coverage 0% → Quality Gate ERROR: JaCoCo 미설정 (위 "테스트" 섹션 참고)
  • Dependency-Check NVD 갱신 실패: Jenkins 에 nvd-api-key credential 이 없다. 폐쇄망/키 부재 시에는 UPDATE_NVD=false 로 실행해 캐시 DB 로만 검사한다.

JNDI 설정 필수

dev 를 포함한 모든 환경에서 WAS 에 JNDI 리소스가 있어야 한다:

  • jdbc/dsOBP_EMS → Portal 데이터베이스
  • jdbc/dsOBP_AGW → Gateway 데이터베이스

환경 변수

# 선택사항: 기본 설정 오버라이드
JAVA_OPTS="-Xmx2g -Xms1g -Dspring.profiles.active=prod"

Docker 배포

# WAR 빌드
gradle bootWar

# Docker 이미지 빌드 (build_docker.sh 는 없다)
docker build -t eapim-portal:latest .

# 컨테이너 실행
docker run -p 30200:30200 \
  -e JAVA_OPTS="-Dspring.profiles.active=prod" \
  -v /Log:/Log \
  eapim-portal:latest

관련 모듈

다음 항목에 영향을 주는 변경 시:

  • Gateway API 명세: elink-online-core-jpa 모듈 확인
  • 공통 유틸리티: elink-portal-common 모듈 확인
  • 암호화: kjb-safedb 모듈 — 현재 빌드에서 제외됨 (위 "멀티 모듈 구조" 참고)
  • Admin 포털: ../eapim-admin/ 관련 프로젝트
  • Online 포털: ../eapim-online/ 관련 프로젝트

추가 자료

  • 사용자 가이드 (한글): 개발자포탈.md
  • 로컬 기동 가이드 (Windows/Eclipse): BOOTRUN_SETUP_GUIDE.md
  • 개발환경 준비, OHS 정적리소스 설정: djb-docs/
  • 메뉴 관리 개발 가이드: readme-docs/메뉴-관리-개발-가이드.md
  • SASS/프론트 빌드: package.json, sass-build.sh, tools/forge-entry.js
  • Docker: Dockerfile
  • CI 설정: Jenkinsfile.*, sonar-project.properties, ci/