532 lines
17 KiB
Markdown
532 lines
17 KiB
Markdown
# 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 브랜치 전략
|
|
|
|
**저장소 정보:**
|
|
- 기본 저장소: `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를 통한 병합만 허용
|
|
|
|
**브랜치 사용 가이드:**
|
|
```bash
|
|
# 개발 시작 시 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 단독 실행
|
|
- JDK/Gradle 환경 변수는 저장소 루트의 `.envrc`(direnv)로 자동 설정됨 (JAVA_HOME → Zulu JDK 8, GRADLE_USER_HOME → 격리 디렉터리)
|
|
|
|
```bash
|
|
# dev 프로파일로 실행 (기본값)
|
|
gradle bootRun
|
|
|
|
# 특정 프로파일로 실행
|
|
gradle bootRun --args='--spring.profiles.active=stage'
|
|
```
|
|
|
|
### 빌드
|
|
|
|
```bash
|
|
# Spring Boot 실행 가능 WAR 빌드
|
|
gradle bootWar
|
|
# 출력: build/libs/eapim-portal-boot.war
|
|
|
|
# 애플리케이션 서버용 표준 WAR 빌드 (JEUS/WebLogic)
|
|
gradle war
|
|
# 출력: build/libs/eapim-portal.war
|
|
|
|
# 클린 후 빌드
|
|
gradle clean build
|
|
```
|
|
|
|
### 테스트
|
|
|
|
```bash
|
|
# 모든 테스트 실행
|
|
gradle test
|
|
|
|
# 커버리지와 함께 테스트 실행
|
|
gradle test --info
|
|
|
|
# 특정 테스트 클래스 실행
|
|
gradle test --tests "com.eactive.apim.portal.apps.user.AccountControllerTest"
|
|
|
|
# 패턴에 매칭되는 테스트 실행
|
|
gradle test --tests "*Controller*"
|
|
```
|
|
|
|
### 개발
|
|
|
|
```bash
|
|
# 현재 프로파일 확인
|
|
gradle printProfile
|
|
|
|
# 소스 세트 설정 확인
|
|
gradle printSourceSets
|
|
|
|
# Docker 이미지 빌드
|
|
./build_docker.sh
|
|
```
|
|
|
|
## 아키텍처
|
|
|
|
### 멀티 모듈 구조
|
|
|
|
이 프로젝트는 Gradle composite build를 통해 3개의 외부 모듈에 의존합니다:
|
|
|
|
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 지원
|
|
- 공통 예외 핸들러 및 보안 유틸리티
|
|
|
|
3. **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 데이터베이스를 사용합니다:
|
|
|
|
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 명세, 서비스, 메시지
|
|
|
|
설정: `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/`)
|
|
|
|
두 가지 사용자 유형:
|
|
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/proxy/`, `apps/sample/`)
|
|
|
|
- Gateway 서버로의 Forward Proxy
|
|
- 요청/응답 로깅이 있는 API 테스터
|
|
- 여러 언어의 샘플 코드 생성
|
|
- API 문서를 위한 Swagger UI 통합
|
|
|
|
### 감사 추적 (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.yml`의 `pages` 섹션에 라우트 설정 (또는 `@GetMapping`/`@PostMapping`으로 직접 매핑)
|
|
|
|
### 메뉴/네비게이션 항목 추가하기
|
|
|
|
**중요:** 메뉴 정의가 **두 곳으로 분리**되어 있다. yml 한 곳만 고치면 헤더 드롭다운에 안 보이고, 헤더만 고치면 브레드크럼이 비어 보인다. 메뉴 추가/이름 변경/순서 변경 시 **반드시 두 파일을 같이 수정**한다.
|
|
|
|
1. **`application.yml`의 `page:` 트리** (브레드크럼·페이지 메타용)
|
|
- `PageService`가 URL → breadcrumb 매핑에 사용
|
|
- 부모 메뉴(`service`, `apis`, `community` 등) 아래 `children:`에 새 키를 추가
|
|
```yaml
|
|
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.yml`의 `portal.pages` 매핑 섹션, 또는 `@GetMapping`)
|
|
```yaml
|
|
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 사용:
|
|
|
|
```java
|
|
@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 리포지토리 메서드 사용 권장:
|
|
|
|
```java
|
|
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 사용:
|
|
```java
|
|
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`의 로깅 설정:
|
|
```yaml
|
|
logging:
|
|
file:
|
|
path: /Log/App/eapim/
|
|
level:
|
|
com.eactive.apim.portal: DEBUG
|
|
org.hibernate.SQL: DEBUG (개발 환경만)
|
|
```
|
|
|
|
Lombok의 `@Slf4j`와 함께 SLF4J 사용:
|
|
```java
|
|
@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` 사용
|
|
|
|
### 일반적인 테스트 패턴
|
|
|
|
```java
|
|
@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 암호화가 비활성화됩니다. 필요한 경우:
|
|
```bash
|
|
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 데이터베이스
|
|
|
|
### 환경 변수
|
|
|
|
```bash
|
|
# 선택사항: 기본 설정 오버라이드
|
|
JAVA_OPTS="-Xmx2g -Xms1g -Dspring.profiles.active=prod"
|
|
```
|
|
|
|
### Docker 배포
|
|
|
|
```bash
|
|
# WAR 빌드
|
|
gradle bootWar
|
|
|
|
# Docker 이미지 빌드
|
|
./build_docker.sh
|
|
|
|
# 컨테이너 실행
|
|
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`
|
|
- 빌드 스크립트: `build-gf63.sh`, `deploy_portal.sh`, `deploy_portal2.sh`
|
|
- Docker: `Dockerfile`, `build_docker.sh`
|
|
- SQL 스크립트: `../kjb-eapim-sql/`
|