15 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 (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 브랜치 전략
저장소 정보:
- 기본 저장소:
ssh://git@192.168.240.178:18081/eapim/eapim-portal.git - 대체 저장소:
https://git.eactive.synology.me:8090/kjb-eapim/eapim-portal.git
브랜치:
-
jenkins_with_weblogic: Jenkins 빌드와 WebLogic 테스트를 위한 브랜치 (기본 개발 브랜치)
- Jenkins CI/CD 파이프라인 설정 포함
- WebLogic 배포 및 테스트 환경 설정
- 일상적인 개발 작업은 이 브랜치에서 수행
- 기능 개발, 버그 수정, 테스트 등 모든 개발 활동의 기본 브랜치
-
master: 완벽히 동작하는 검증된 코드 저장소 (안정 브랜치)
- 프로덕션 배포 가능한 안정적인 코드만 포함
- jenkins_with_weblogic 브랜치에서 충분히 테스트된 코드만 병합
- 직접 커밋 금지, Pull Request를 통한 병합만 허용
브랜치 사용 가이드:
# 개발 시작 시 jenkins_with_weblogic 브랜치에서 작업
git checkout jenkins_with_weblogic
# 기능 개발 후 커밋
git add .
git commit -m "기능 설명"
# jenkins_with_weblogic 브랜치에 푸시
git push origin jenkins_with_weblogic
# 충분한 테스트 완료 후 master로 병합 (Pull Request 사용)
빌드 명령어
애플리케이션 실행
- gradlew 사용 금지 - offline gradle 단독 실행
- msi-gf63 컴퓨터에서는 /c/eactive/workspaces/shell-scripts/kjb-gradle.sh 로 gradle 실행 (jdk, gradle 등 환경 변수 세팅 후 gradle 실행하는 스크립트)
# dev 프로파일로 실행 (기본값)
gradle bootRun
# 특정 프로파일로 실행
gradle bootRun --args='--spring.profiles.active=stage'
빌드
# Spring Boot 실행 가능 WAR 빌드
gradle bootWar
# 출력: build/libs/eapim-portal-boot.war
# 애플리케이션 서버용 표준 WAR 빌드 (JEUS/WebLogic)
gradle war
# 출력: build/libs/eapim-portal.war
# 클린 후 빌드
gradle clean build
테스트
# 모든 테스트 실행
gradle test
# 커버리지와 함께 테스트 실행
gradle test --info
# 특정 테스트 클래스 실행
gradle test --tests "com.eactive.apim.portal.apps.user.AccountControllerTest"
# 패턴에 매칭되는 테스트 실행
gradle test --tests "*Controller*"
개발
# 현재 프로파일 확인
gradle printProfile
# 소스 세트 설정 확인
gradle printSourceSets
# Docker 이미지 빌드
./build_docker.sh
아키텍처
멀티 모듈 구조
이 프로젝트는 Gradle composite build를 통해 3개의 외부 모듈에 의존합니다:
-
elink-online-core-jpa (
../eapim-online/elink-online-core-jpa)- Gateway 데이터 모델 및 JPA 엔티티
- API 명세 엔티티 및 리포지토리 제공
- 패키지:
com.eactive.eai.data.entity.onl.*
-
elink-portal-common (
../elink-portal-common)- 공유 포털 유틸리티 및 공통 컴포넌트
- 기본 리포지토리 구현, QueryDSL 지원
- 공통 예외 핸들러 및 보안 유틸리티
-
kjb-safedb (
../kjb-safedb)- 광주은행 SafeDB 암호화 라이브러리
- 데이터베이스 레벨 민감 데이터 암호화
- 암호화 컬럼(사용자 비밀번호, API 키 등)에 필수
패키지 구조
코드는 기술 계층이 아닌 기능 모듈(수직 분할) 방식으로 구성됩니다:
com.eactive.apim.portal/
├── apps/ # 기능 모듈
│ ├── agreements/ # API 약관
│ ├── apis/ # API 카탈로그 & 문서
│ ├── apiservice/ # API 서비스 그룹핑
│ ├── app/ # API 키 관리
│ ├── approval/ # 승인 워크플로우
│ ├── auth/ # 인증
│ ├── community/ # FAQ, 공지사항, Q&A, 제휴문의
│ ├── dashboard/ # 통계 & 분석
│ ├── file/ # 파일 업로드/다운로드
│ ├── login/ # 로그인/로그아웃
│ ├── proxy/ # API 테스트용 Forward Proxy
│ ├── sample/ # 샘플 코드 생성
│ └── user/ # 사용자 관리
├── common/ # 공통 관심사
├── config/ # Spring 설정
└── gateway/ # Gateway DB 직접 접근
└── data/ # Gateway 리포지토리
각 기능 모듈은 일반적으로 다음을 포함합니다:
controller/- Spring MVC 컨트롤러 (@Controller)service/- 비즈니스 로직 (@Service, @Transactional)repository/- Spring Data JPA 리포지토리dto/- 데이터 전송 객체 (Lombok @Data)mapper/- MapStruct 인터페이스 (entity ↔ DTO 변환)
이중 데이터베이스 아키텍처
애플리케이션은 두 개의 Oracle 데이터베이스를 사용합니다:
-
EMS Database (Portal/Admin)
- JNDI:
jdbc/dsOBP_EMS - Schema:
EMSADM - Entities:
com.eactive.apim.portal.apps.* - 목적: 포털 사용자, 조직, API 키, 승인
- JNDI:
-
Gateway Database (API Specs)
- JNDI:
jdbc/dsOBP_AGW - Schema:
AGWADM - Entities:
com.eactive.eai.data.entity.onl.* - 목적: API 명세, 서비스, 메시지
- JNDI:
설정: config/PortalDatasourceConfiguration.java
- 각 데이터베이스별 별도 EntityManager
- Atomikos JTA를 통한 분산 트랜잭션
- 트랜잭션 로그:
/Log/eapim/portal/
설정 프로파일
환경별 설정 파일: src/main/resources/application-{profile}.yml
- dev: 개발 환경 (Oracle at 192.168.240.177:1599, DevTools 활성화, SQL 로깅)
- stage: 스테이징 환경 (JNDI 데이터소스, proxy to inter-dapiwas01)
- prod: 운영 환경 (JNDI 데이터소스, proxy to inter-apiwas00, 캐싱 활성화)
- gf63: 개인 개발 환경
- kjb_rinjae: 개인 개발 환경
주요 설정:
- 세션 타임아웃: 15분
- 파일 업로드 최대: 8MB
- 비밀번호 만료: 90일
- 인증 토큰 TTL: 5분 (300초)
- 사용자 승인 필수: true
주요 기능 및 비즈니스 로직
사용자 관리 (apps/user/)
두 가지 사용자 유형:
- 내부 사용자 (Staff): 포털 관리자 및 운영자
- 기업 사용자 (Enterprise): 외부 API 소비자
사용자 라이프사이클:
- 가입 → 이메일 인증 → 관리자 승인 → 활성화
- 비밀번호 정책 적용 (90일 만료, 복잡도 규칙)
- 로그인 실패 시 계정 잠금
- 휴면 계정 관리
API 키 관리 (apps/app/)
API 키는 승인 워크플로우와 함께 관리됩니다:
- 기업 관리자가
AppRequestController를 통해 키 요청 - 관리자가
ApprovalController를 통해 승인/반려 - 키는 개발/운영 환경 지원
- 키는 eLink Gateway ClientID/ClientSecret과 연결
승인 워크플로우 (apps/approval/)
다음 항목에 대한 범용 승인 시스템:
- 사용자 등록 승인
- API 키 생성/수정
- 제휴 신청
엔티티: Approval, Approver, ApprovalStatus (WAITING, APPROVED, REJECTED)
API 테스트 (apps/proxy/, apps/sample/)
- Gateway 서버로의 Forward Proxy
- 요청/응답 로깅이 있는 API 테스터
- 여러 언어의 샘플 코드 생성
- API 문서를 위한 Swagger UI 통합
감사 추적 (Hibernate Envers)
모든 엔티티는 자동 감사를 위해 AbstractAuditingEntity를 확장합니다:
createdBy,createdDatelastModifiedBy,lastModifiedDate@Audited어노테이션으로 변경 이력 관리- Spring Data Envers를 통한 이력 조회
공통 개발 패턴
새 기능 모듈 추가하기
apps/하위에 패키지 생성 (예:apps/newfeature/)controller/,service/,repository/,dto/,mapper/로 구조화repository/entity/에 JPA 엔티티 생성 (AbstractAuditingEntity확장)dto/에 Lombok@Data를 사용한 DTO 생성mapper/에 MapStruct 매퍼 인터페이스 생성@Service와@Transactional을 사용한 서비스 계층 구현@Controller와@RequestMapping을 사용한 컨트롤러 생성src/main/resources/templates/views/newfeature/에 Thymeleaf 템플릿 추가application.yml의pages섹션에 라우트 설정 (또는@GetMapping/@PostMapping으로 직접 매핑)
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 방어
- Lucy 필터를 통한 XSS 방어
역할 계층:
ROLE_USER → [ROLE_INQUIRY, ROLE_ACCOUNT]
ROLE_CORP_USER → [ROLE_INQUIRY, ROLE_APP, ROLE_ACCOUNT]
ROLE_CORP_MANAGER → [ROLE_API_KEY_REQUEST, 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) - 다중 데이터베이스: Atomikos JTA가 자동으로 분산 트랜잭션 처리
에러 처리
common/exception/의 글로벌 예외 처리:
@ControllerAdvice가 적용된GlobalExceptionHandler- 커스텀 예외는
RuntimeException확장 - Thymeleaf 에러 뷰 또는 AJAX 요청에는 JSON 반환
로깅
application.yml의 로깅 설정:
logging:
file:
path: /Log/App/eapim/
level:
com.eactive.apim.portal: DEBUG
org.hibernate.SQL: DEBUG (개발 환경만)
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 암호화가 비활성화됩니다. 필요한 경우:
gradle test -Dsafedb=/path/to/safedb
중요 사항
한글 지원
이 포털은 한글을 광범위하게 사용합니다:
- Thymeleaf 템플릿은 한글 레이블 사용
- 데이터베이스는 한글 데이터 포함 (UTF-8)
- 한글 메시지 프로퍼티 (
messages_ko.properties) - 한글 사용자 가이드 (
개발자포탈.md)
Forward Proxy 설정
API 테스트는 Gateway로의 Forward Proxy 사용:
- Dev:
http://localhost:10000 - Stage:
http://inter-dapiwas01:10000 - Prod:
http://inter-apiwas00:10000
설정: apps/proxy/service/ProxyService.java
비밀번호 정책
PortalUserValidator에서 적용:
- 최소 8자
- 대문자, 소문자, 숫자, 특수문자 포함 필수
- 연속된 문자 사용 불가
- 최근 3개 비밀번호 재사용 불가
- 90일 후 만료
세션 관리
- 사용자당 단일 세션 강제
- 세션 타임아웃: 15분
- 로그인 시 세션 고정 공격 방어
- Redis/Ehcache를 통한 세션 클러스터링 (스테이징/운영)
파일 업로드 제한
- 최대 파일 크기: 8MB
FileService에서 허용 확장자 설정- 파일 저장 위치:
/Log/App/eapim/files/ - 업로드 시 XSS 스캐닝
배포
애플리케이션 서버 지원
WAR 파일 호환 서버:
- JEUS (
jeus-web-dd.xml필요) - WebLogic (
weblogic.xml필요) - Tomcat (Spring Boot 내장)
JNDI 설정 필수
스테이징/운영 환경에서 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 run -p 8080:8080 \
-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 - 빌드 스크립트:
build-gf63.sh,deploy_portal.sh,deploy_portal2.sh - Docker:
Dockerfile,build_docker.sh - SQL 스크립트:
../kjb-eapim-sql/