common-api — 이슈·트러블슈팅 내역
대상: 인증·권한(lx.svcauth), UserForge(lx.gygo.userdataset), 공통 인프라
목차
- 빌드·의존성
- Redis·캐시
- 보안약점 진단 대응
- 런타임 오류·API 응답
- 인증·권한(Auth)
- UserForge(사용자 맞춤 데이터셋)
- 로컬 개발 체크리스트
- 알려진 제약·후속 과제
1. 빌드·의존성
1-1. Nexus 의존성 다운로드 실패
항목내용
| 증상 | ./gradlew compileJava 또는 bootRun 시 Maven 아티팩트 resolve 실패 |
| 원인 | 사내 Nexus(build.gradle의 192.168.211.22:8081) 접근 불가 — VPN·사내망 미연결 |
| 조치 | VPN 연결 후 재시도. URL 변경 이력 있음(5ea8536 — MAVEN Nexus 주소 변경) |
| 예방 | CI·로컬 모두 Nexus 접근 가능 환경에서 빌드 |
./gradlew compileJava --refresh-dependencies
1-2. SSO JAR 누락으로 빌드 실패
항목내용
| 증상 | exlibs/WAJavaAPI_*.jar, exlibs/lxkeyiden_*.jar 관련 compile error |
| 원인 | build.gradle이 implementation files('exlibs/...') 로 로컬 JAR 참조 |
| 조치 | 저장소에 exlibs/ 디렉터리·JAR 존재 확인. 없으면 팀에서 JAR 수령 후 배치 |
1-3. 보안약점 보완 후 컴파일 오류
항목내용
| 증상 | Code-Ray/보안 보완 커밋 이후 AuthServiceImpl 등에서 컴파일 에러 |
| 대표 커밋 | c4698fc(66p까지 빌드 오류 해결), 8f37a79(빌드에러 해결) |
| 원인 예 | null 체크 추가 시 주석 처리된 for-loop 변수(lxMemberEach)를 참조하는 코드 잔존 |
| 조치 | 보완 PR 머지 후 ./gradlew compileJava 로 즉시 검증. 주석·리팩터링 잔여 코드 정리 |
1-4. SpotBugs 경고
항목내용
| 설정 | build.gradle — ignoreFailures = true, config/spotbugs/exclude.xml |
| 제외 패턴 | DTO EI_EXPOSE_REP, Spring @Service 생성자 주입 EI_EXPOSE_REP2, auth domain 필드 등 |
| 참고 | NP_*(null pointer) 패턴은 별도 Code-Ray 진단과 SpotBugs를 함께 참고 |
2. Redis·캐시
2-1. Redis 연결 실패 (운영·개발 환경)
항목내용
| 증상 | 기동 시 Redis connection refused, 캐시·토큰 관련 기능 오동작 |
| 원인 | 인프라 IP 변경 후 application-*.yml 미반영. dev/prod Redis host·password 불일치 |
| 조치 | 커밋 291e793(레디스 문제) — dev/prod Redis host를 192.168.211.x 대역으로, password authredis 로 정합 |
| 로컬 | spring.redis.host: localhost, 비밀번호 없음 — docker compose up -d 로 Redis 기동 |
# 프로젝트 루트
docker compose up -d
redis-cli ping # PONG 확인
2-2. 로컬 Redis 미기동
항목내용
| 증상 | local 프로필에서 Spring Boot 기동 실패 또는 cache/redis bean error |
| 조치 | README 4절 — Redis 6379 포트로 기동. 포트 변경 시 application-local.yml의 spring.redis 수정 |
3. 보안약점 진단 대응
행정안전부 SW 보안약점 진단(Code-Ray 등) 대응이 2026년 4~6월에 집중 반영되었습니다. 관련 커밋: 0633322 ~ 60a1dac (40p → 159p 구간).
3-1. CWE-476 — Null Pointer 역참조
항목내용
| 위험도 | 중간 |
| 증상 | 정적 분석 도구가 xxx.trim(), list.get(0), Map 역참조 등 지적 |
| 대응 | NullSafeStrings, NullSafeCollections, MapUtil null-safe 메서드 도입·확산 |
| 적용 범위 | AuthServiceImpl, UserDatasetService, Shapefile import/export 서비스 등 |
| 참고 문서 | docs/null-pointer.md |
패턴 예시 (Before → After):
// Before — trim() null 역참조 가능
String id = rawId.trim();
// After
String id = NullSafeStrings.trimOrEmpty(rawId);
// Before — MyBatis 결과 list null 가능
for (UserDatasetRow row : rows) { ... }
// After
for (UserDatasetRow row : NullSafeCollections.listOrEmpty(rows)) { ... }
Revert 이력: 66e1484 Revert "CWE-476" — 일부 변경 롤백 후 bc4d28e에서 재보완. 대규모 null-safe 리팩터링 시 기능 회귀·빌드 오류를 ./gradlew test compileJava로 확인할 것.
3-2. CWE-489 — Leftover Debug Code (오탐)
항목내용
| 지적 대상 | SvcAuthApplication.main(String[] args) |
| 판단 | 오탐(False Positive) — Spring Boot 표준 진입점, 디버그 출력·백도어 없음 |
| 조치 | 클래스 Javadoc에 오탐 근거 명시. 삭제 시 JAR 기동 불가 |
| 참고 문서 | docs/security-finding-mainmethod-falsepositive.md |
3-3. CWE-390 — Unchecked Error Condition
항목내용
| 대응 | UserDatasetShapefileDbfExportService 등 — 예외·리턴값 검증 보강 (95ade98) |
| 요지 | DBF/파일 I/O 실패를 무시하지 않고 명시적 처리 |
3-4. CWE-754 — Improper Check for Unusual or Exceptional Conditions
항목내용
| 대응 | UserDatasetService — catch (Exception) 과다 포괄을 IOException, DataAccessException 등으로 한정 |
| 추가 | runCommonDao() 래퍼로 DAO 호출 예외를 DataAccessResourceFailureException으로 변환 |
| Shapefile | InvalidPathException, DBFException 등 구체 예외 분기 |
3-5. debug 구문·미사용 로그 정리
항목내용
| 커밋 | 01fb72b — debug 구문이 사용되지 않도록 수정 |
| 범위 | UserDatasetService, Shapefile import/export, JwtRequestFilter 등 |
| 조치 | System.out, 불필요 log.debug 제거 — 진단 도구의 “디버그 코드” 항목 재지적 방지 |
4. 런타임 오류·API 응답
4-1. 공통 에러 응답 구조
대부분의 API는 HTTP 200 + 본문 resCode/errCode로 실패를 전달합니다.
{
"reqId": "...",
"resCode": "P001",
"resData": {},
"errCode": "E005",
"errMsg": "인증 되지 않았습니다 | ..."
}
errCode의미흔한 원인
| E001 | 요청값 오류 | 필수 필드 누락, Bean Validation 실패 |
| E005 | 미인증 | JWT·X-User-Id 없음 |
| E006 | 미인가 | 타 사용자 리소스 접근 |
| E009 | 데이터 없음 | 존재하지 않는 datstId/rcrdId |
| E012 | reqId 없음 | /auth-service/auth에 잘못된 reqId |
| E014~`E018` | JWT 오류 | 만료, 형식, 서명, 로그아웃 토큰 |
| E031 | NPE | 내부 null 참조 — NullPointerException → AbstractRestHandler에서 매핑 |
4-2. E031 (NullPointerException) 운영 대응
항목내용
| 증상 | errCode: E031, 메시지 “필수 값 누락 또는 null 참조…” |
| 원인 | 요청 body null, DB/MyBatis 결과 null, 파일 메타 리스트에 null 항목 |
| 대응 커밋 | 878e4a6, 8c9500c, d103bd0 |
| 조치 | 컨트롤러에서 Objects.requireNonNull(req), 서비스에서 NullSafeCollections·null skip loop |
로컬 디버깅: application-*.yml의 api.debug-expose-exception: true(기본)이면 E000 등에 예외 클래스·메시지가 포함됩니다. 운영에서는 false 권장.
4-3. JSON 파싱 오류 (E000)
항목내용
| 증상 | HttpMessageNotReadableException → “잘못된 JSON 형태입니다…” |
| 원인 | Content-Type 미지정, 키 따옴표 누락, trailing comma |
| 조치 | Content-Type: application/json, Swagger 예시 본문 그대로 전송 |
4-4. multipart 업로드 실패
항목내용
| 증상 | 대용량 ZIP 업로드 시 413 또는 connection reset |
| 설정 | spring.servlet.multipart.max-file-size: 64MB, max-request-size: 1024MB, Tomcat max-http-form-post-size: 1024MB |
| 조치 | 프록시(Nginx/API Gateway) 별도 body size limit 확인. Gateway limit < 앱 limit 이면 Gateway에서 먼저 차단됨 |
5. 인증·권한(Auth)
5-1. 로그인·토큰 (AUTH_REQ001~003)
증상가능 원인확인
| E010 사용자 없음 | DB 사용자 미등록, userIden 불일치 | reqData의 로그인 ID |
| E007 비밀번호 불일치 | 평문·해시 정책 불일치 | AUTH_REQ001 요청 본문 |
| E014 토큰 만료 | access token TTL 경과 | AUTH_REQ003으로 재발급 |
| E016 로그아웃 토큰 | 이미 로그아웃 처리된 access token | 재로그인 |
| E017 refresh 없음 | Redis/DB에 refresh token 없음 | Redis 연결·세션 저장 확인 |
5-2. SSO (AUTH_REQ004~005)
증상errCode조치
| ssoToken 없음 | E022 | WeLand 리다이렉트 파라미터 확인 |
| keyValue 없음 | E019 | 지자체 Key SSO keyValueB64Encode 전달 확인 |
| 복호화 실패 | E021/E024 | exlibs JAR·RSA 키 설정(ssoweland, key SSO 키) |
| keyValue 재사용 | E028 | 동일 암호문 재전송 — 새로 발급 필요 |
5-3. JWT 필터·헤더
JwtRequestFilter는 다음 순서로 토큰 추출:
- Authorization: Bearer ...
- 커스텀 access token 헤더
- 쿼리/쿠키 파라미터 파싱
토큰 검증 실패 시 SecurityContext 미설정 → 이후 API는 E005.
개발/테스트: Postman 등에서 X-User-Id: {loginId} 헤더만으로 UserForge API 호출 가능(JWT 없이).
5-4. 공통코드 서비스 연동
항목내용
| 증상 | 인증·메뉴 API에서 외부 코드 조회 실패 |
| 조치 | 291e793 — commoncodeservice.host를 http://192.168.211.52:8000 으로 변경 |
| 확인 | 해당 호스트 reachable, /code-service/getCdAllByCdLclas.do 응답 |
6. UserForge(사용자 맞춤 데이터셋)
6-1. 파일 저장 경로(NAS) 오류 — E004
항목내용
| 증상 | 데이터셋 등록·ZIP 저장 시 FileStorageException → E004 |
| 원인 | userforge.storage.path 디렉터리 없음, Windows/Linux 경로 불일치, NAS 마운트 실패 |
| 조치 | application-local.yml / application-lxdev.yml / application-lxprod.yml 에 환경별 path 설정 (8260920 — lxdev/lxprod NAS 경로 추가) |
| 로컬 | D:/... 등 본인 PC에 디렉터리 생성 후 경로 수정 (README 7절) |
저장 구조: {basePath}/user-datasets/{userId}/{datasetId}/{filename}.zip
6-2. Shapefile ZIP 업로드·미리보기
증상원인조치
| 미리보기 geometry 없음 | ZIP 내 .shp 없음, 좌표계 미지원 | ZIP 구조·CRS 확인 |
| DBF 속성 깨짐 | 인코딩(EUC-KR/CP949) | ShapefileDbfAttributesService charset 처리 |
| 레이어 다수 SHP | 단일 shp만 가정한 초기 버전 | 67208e6 — 다중 SHP 속성 CRUD 보완 |
2단계 저장 플로우:
- POST .../shp-geometry/preview — DB 저장 전 geometry 확인
- POST .../{datstId}/main-zip — 본 저장
미리보기 없이 본 저장만 호출하면 geometry·속성 불일치 가능.
6-3. SHP 재등록·ROW DATA 불러오기
항목내용
| 증상 | 기존 데이터셋에 SHP 재업로드 후 속성·original cells 불일치 |
| 커밋 | 19b5b2b — SHP 파일 재등록 및 ROW DATA 불러오기 기능 보완 |
| 추가 API | GET .../records/{rcrdId}/original-cells — 초기화 미리보기 |
| 조치 | reset 플래그·shpRelativePath(다중 레이어) 파라미터 확인 |
6-4. 컬럼(필드) 추가·삭제·이름 변경
항목내용
| 증상 | PUT .../update/{datstId} 후 필드 순서·이름·삭제 반영 안 됨 |
| 커밋 | c1090fb, b65a794, 67208e6 |
| 조치 | UserDatasetUpdateReq.fields, attributeCellOverrides 스키마 준수. 컨트롤러에서 @Valid/checkReqValue 통과 확인 |
6-5. 다중 SHP 레이어·속성 CRUD
항목내용
| 배경 | ZIP 하나에 .shp가 여러 개인 경우 레이어별 geometry·DBF 행 관리 필요 |
| 커밋 | 67208e6 (+2100 lines) — ShpLayerGeometryDto, ShpLayerAttributeRowsDto, export/import 전면 보강 |
| 증상 | 특정 레이어만 수정했는데 전 레이어 덮어쓰기 |
| MyBatis | userdatasetfield.xml, userdatasetrow.xml 쿼리 동시 변경 — 배포 시 mapper XML 누락 주의 |
6-6. 데이터셋 검색·목록
항목내용
| 커밋 | 890c76b — 검색 필터링 로직 추가 |
| 증상 | 검색 결과 누락 |
6-7. MapUtil·selectKey 타입 불일치
항목내용
| 증상 | insert 후 PK 추출 시 ClassCastException 또는 E030 |
| 조치 | MapUtil.requireLongObject(), requireLongKey() — MyBatis selectKey 반환 타입(Long/Integer) 통일 처리 (d103bd0) |
7. 로컬 개발 체크리스트
기동 실패 시 아래 순서로 확인합니다.
#확인 항목명령/위치
| 1 | JDK 15 | java -version |
| 2 | VPN → Nexus | ./gradlew compileJava |
| 3 | Redis 6379 | docker compose up -d |
| 4 | PostgreSQL + PostGIS | application-local.yml → spring.datasource.hikari.primary |
| 5 | search_path | SET search_path TO "GYGO", public (connection-init-sql) |
| 6 | exlibs/ JAR | SSO JAR 존재 |
| 7 | userforge.storage.path | 디렉터리 생성·쓰기 권한 |
| 8 | Active profile | 기본 local (application.yml) |
| 9 | 포트 8029 | server.port 충돌 없음 |
기동 후 스모크 테스트:
GET http://localhost:8029/swagger-ui/index.html
GET http://localhost:8029/api/user-datasets/list
X-User-Id: {테스트로그인ID}
POST http://localhost:8029/auth-service/auth
Content-Type: application/json
{ "reqId": "AUTH_REQ001", "reqData": { ... } }
8. 알려진 제약·후속 과제
구분내용
| HTTP 상태 코드 | 전역 핸들러 특성상 다수 API가 실패 시에도 HTTP 200 — 클라이언트는 resCode/errCode로 판단 필요 (api-spec.md 0-1절) |
| 이중 DB | primary/secondary Hikari — Gygo 기능은 주로 primary. secondary 용도는 lx.svcauth.config.DB 참고 |
| Spring Boot 2.7 / Java 15 | LTS 아님 — 장기적으로 JDK·Boot 업그레이드 검토 |
| WebSocket 샘플 | ChatWebSocketConfig — /chat-sample-service/ws, SockJS, setAllowedOriginPatterns("*") (58b41b0 소켓설정). 운영 CORS 정책 별도 검토 |
| Code-Ray 대량 보완 | 40p→159p 구간 다수 커밋 — 회귀 테스트(인증 로그인, 데이터셋 CRUD, Shapefile 업로드) 권장 |
| 민감 설정 | DB password, JWT secret, Redis password — 저장소 커밋 지양, 환경 변수·Config Server 주입 |
부록: 관련 커밋 타임라인 (요약)
시기커밋 메시지 (요지)영역
| 2026-04 | 데이터셋 CRUD, SHP 업로드, 검색, NAS 경로 | UserForge |
| 2026-04 | SHP 재등록·ROW DATA, 컬럼 추가/삭제 | UserForge |
| 2026-04 | Nexus 주소 변경, Redis/commoncode host 변경 | 인프라 |
| 2026-04~05 | CWE-390/476/754, 보안약점 40p~159p | 전역 |
| 2026-05 | 다중 SHP 속성 CRUD 대규모 보완 | UserForge |
| 2026-06 | NPE 처리, NullSafe 유틸, debug 구문 제거, 빌드에러 | 전역·UserForge·Auth |
| 2026-06 | WebSocket 설정 | chat-sample |
참고 문서
문서설명
| README.md | 로컬 설치·실행 |
| api-spec.md | API 명세·공통 에러 코드 |
| null-pointer.md | CWE-476 가이드 |
| security-finding-mainmethod-falsepositive.md | CWE-489 오탐 회신 |
| blog-gygo-svc3d-back-common-api.md | 프로젝트 소개 블로그 |
문서 버전: 1.0 · user-loc 도메인 이슈는 본 문서 범위에서 제외했습니다.
'TroubleShooting' 카테고리의 다른 글
| [TroubleShooting] 레이스 컨디션 버그를 해결한 경험 (0) | 2026.07.07 |
|---|---|
| [TroubleShooting] 번들 사이즈 30% 줄인 과정 (0) | 2026.07.07 |
| [TroubleShooting] 3D 지형 종/횡단면 분석 기능 이슈 해결 (0) | 2026.07.06 |
| [TroubleShooting] Gaussian Splatting 이슈 & 트러블슈팅 (0) | 2026.07.03 |
| [TroubleShooting] ml-sharp(feat. Apple) (0) | 2026.07.03 |