공통 백엔드 API를 만나다 — 인증·공간데이터·나의 지역을 하나의 Spring Boot로
common-api 프로젝트 소개
Java 15 · Spring Boot 2.7 · PostgreSQL(PostGIS) · Redis
들어가며
3D 공간정보 서비스를 운영하다 보면, 프론트엔드가 호출해야 할 API가 자연스럽게 여러 갈래로 나뉩니다. 로그인과 권한, 사용자가 직접 올린 Shapefile, 관심 지역(나의 지역) 이미지까지 — 각각 별도 서비스로 쪼개면 배포·인증·공통 응답 형식을 매번 맞춰야 합니다.
gygo-svc3d-back-common-api는 이런 요구를 단일 Spring Boot 애플리케이션으로 묶은 GYGO 3D 서비스의 공통 백엔드입니다. 설정상 서비스명은 auth-service이지만, 실제로는 인증·권한뿐 아니라 UserForge(사용자 맞춤 데이터셋) 와 user-loc(나의 지역) 까지 함께 제공합니다.
이 글에서는 이 프로젝트가 무엇을 하는지, 어떻게 구성되어 있는지, 개발자 관점에서 어떤 점이 특징적인지 정리합니다.
한눈에 보는 역할
영역Base Path설명
| 인증·권한 | /auth-service | JWT 로그인/로그아웃/토큰 검증, WeLand·지자체 Key SSO, 역할·메뉴·API 권한 |
| UserForge | /api/user-datasets | Shapefile/ZIP 업로드, GeoJSON 미리보기, 레코드 CRUD, 셰이프파일 다운로드 |
| 나의 지역 | /user-loc-service | 사용자 관심 장소 등록·조회·수정·삭제, 이미지 첨부 |
| 템플릿 | /template-service | 템플릿 연동용 엔드포인트 |
진입점은 lx.svcauth.SvcAuthApplication 하나이며, lx.svcauth, lx.gygo, gygo 패키지를 스캔합니다.
@SpringBootApplication(scanBasePackages = {"lx.svcauth", "lx.gygo", "gygo"})
public class SvcAuthApplication {
public static void main(String[] args) {
SpringApplication.run(SvcAuthApplication.class, args);
}
}
아키텍처 개요
┌─────────────────────────────────────────────────────────────┐
│ gygo-svc3d-back-common-api (Spring Boot) │
├──────────────┬────────────────────┬───────────────────────────┤
│ lx.svcauth │ lx.gygo.userdataset│ lx.gygo.userloc │
│ Auth/Security│ UserForge API │ 나의 지역 API │
│ 공통 ResStd │ Shapefile·GeoJSON │ 이미지 스토리지 │
└──────┬───────┴─────────┬──────────┴───────────┬─────────────┘
│ │ │
▼ ▼ ▼
PostgreSQL 파일 스토리지 NAS/로컬 경로
(PostGIS, gygo) (userforge.storage) (userloc.storage)
│
▼
Redis (캐시·세션)
왜 모놀리식인가?
- 공통 응답·예외 처리를 AbstractRestHandler 한 곳에서 통일
- 사용자 식별(UserIdResolver)을 JWT·개발용 헤더로 일관되게 적용
- 3D 포탈·운영포탈이 이미 reqId 기반 단일 엔드포인트(/auth-service/auth)에 익숙함
- Shapefile 처리처럼 DB + 파일 I/O가 섞인 작업을 트랜잭션 경계 안에서 다루기 쉬움
마이크로서비스로 쪼개는 것보다 운영 포탈·3D 사용자 포탈이 실제로 쓰는 API 묶음에 맞춘 실용적인 선택에 가깝습니다.
1. 인증·권한 — reqId 하나로 20가지 이상의 업무
인증 API의 특징은 URL 하나, 본문의 reqId로 분기한다는 점입니다.
POST /auth-service/auth
Content-Type: application/json
{
"reqId": "AUTH_REQ001",
"reqData": { ... }
}
AuthController는 reqId 값에 따라 로그인, 로그아웃, 토큰 검증, SSO, 역할·메뉴·API 권한 조회 등을 라우팅합니다.
reqId (예)역할
| AUTH_REQ001 | 로그인 및 JWT 발급 |
| AUTH_REQ002 | 로그아웃 |
| AUTH_REQ003 | 리프레시/액세스 토큰 검증·재발급 |
| AUTH_REQ004 | WeLand SSO |
| AUTH_REQ005 | 지자체 Key SSO (RSA 복호화) |
| AUTH_REQ007 ~ AUTH_REQ020 | 역할, 메뉴, API 권한, 3D 전용 메뉴 등 |
| AUTH_REQ101 ~ AUTH_REQ104 | 개발지원(SPTDEV) 전용 변형 |
SSO 연동
- WeLand SSO: ssoToken 기반 포탈 연동 (AUTH_REQ004)
- Key SSO: 지자체에 RSA 공개키를 제공하고, 암호화된 사용자 ID를 복호화 (AUTH_REQ005)
- WiseAccess(WAJavaAPI), lxkeyiden JAR을 exlibs/에서 로컬 의존성으로 참조
JWT + Redis
- JJWT로 액세스·리프레시 토큰 발급
- Spring Security + 커스텀 AuthenticationEntryPoint / AccessDeniedHandler
- Redis 캐시로 세션·토큰 관련 상태 관리
레거시 포탈과의 호환을 유지하면서, Spring Security 생태계의 필터 체인을 그대로 활용하는 구조입니다.
2. UserForge — 사용자 맞춤 공간 데이터셋
3D 포탈에서 사용자가 직접 Shapefile/ZIP을 올려 지도 위에 올리고, 속성을 편집하는 기능이 UserForge입니다. 패키지는 lx.gygo.userdataset, API prefix는 /api/user-datasets입니다.
할 수 있는 일
- 데이터셋 목록·검색·상세·즐겨찾기
- Shapefile ZIP 업로드 → 미리보기 → 본 저장 2단계 플로우
- DBF 속성 스키마 조회, geometry만 또는 geometry+속성 미리보기
- 필드 추가·삭제·이름 변경·순서 변경, 레코드 CRUD
- 저장된 Shapefile을 ZIP으로 재다운로드
공간 데이터 처리 흐름 (개념)
[클라이언트] ZIP 업로드
│
▼
[서버] ZIP 해제 → .shp/.dbf/.shx 검증
│
├─► 미리보기: geometry → GeoJSON (DB 저장 전)
│
└─► 본 저장: 메타 DB + 파일 스토리지 + PostGIS EWKT/GeoJSON
주요 서비스 클래스:
- UserDatasetService — 데이터셋 생명주기
- UserDatasetRecordService — 레코드(행) 단위 CRUD
- ShapefileDbfAttributesService — DBF 스키마·미리보기
- UserDatasetShapefileImportService — Shapefile 임포트
- LocalFileStorageService — 로컬/NAS 파일 저장
PostGIS search_path는 "GYGO", public으로 설정되어, 앱 스키마와 PostGIS 함수를 함께 사용합니다. 대표 geometry는 EWKT에서 GeoJSON으로 변환하는 RprsGeomEwktToGeoJson 같은 전용 컴포넌트가 있습니다.
API 규모
데이터셋 API 17개 + 레코드 API 6개 수준으로, Swagger 태그는 UserForge, UserForge Records로 구분됩니다. multipart 업로드(최대 64MB 파일, 1GB 요청)를 전제로 Tomcat post size도 넉넉히 잡혀 있습니다.
3. user-loc — 나의 지역(관심 장소)
lx.gygo.userloc 패키지는 사용자가 자주 보는 지역·장소를 등록하고 이미지를 붙이는 API입니다.
- Base path: /user-loc-service
- 헬스 체크: GET /user-loc-service/health
- CRUD: /list, /create, /update, /delete 등
- 이미지는 userloc.storage.path 아래 {login}/{plcId}/ 구조로 저장
- 브라우저 노출 URL은 public-base-url 설정으로 /user-loc-service/files/... 형태
UserForge와 마찬가지로 UserIdResolver로 로그인 사용자를 식별하고, 타 사용자 리소스 접근 시 NotAuthorizedException으로 막습니다.
공통 API 설계 — ResStd와 전역 예외 처리
UserForge·user-loc뿐 아니라 대부분의 API가 ResStd 래퍼로 응답합니다.
{
"reqId": null,
"resCode": "P000",
"resData": { },
"errCode": null,
"errMsg": null
}
- resCode: P000(성공) / P001(실패)
- errCode: E001(요청값 오류), E005(미인증), E006(미인가), E009(데이터 없음) 등
AbstractRestHandler의 @ControllerAdvice가 예외를 HTTP 상태와 별개로 본문의 errCode로 변환합니다. 클라이언트(운영포탈·3D 포탈)는 오래전부터 이 형식에 맞춰져 있어, 새 도메인 API도 같은 패턴을 따릅니다.
사용자 식별 우선순위
- X-User-Id 헤더 — 로컬·통합 테스트용
- Spring Security JWT의 username
둘 다 없으면 E005(인증되지 않음)입니다.
기술 스택 정리
분류기술
| 언어·프레임워크 | Java 15, Spring Boot 2.7, Spring Cloud Config/Bus/Sleuth |
| 웹 | Spring MVC, WebFlux(WebClient), WebSocket, Validation |
| 데이터 | PostgreSQL + PostGIS, JPA + QueryDSL, MyBatis(듀얼 datasource) |
| 캐시 | Redis, EhCache |
| 보안 | Spring Security, JJWT |
| 문서 | SpringDoc OpenAPI (Swagger UI) |
| 품질 | SpotBugs, SonarQube Gradle 플러그인 |
| 기타 | egovframe RTE 일부, javadbf(Shapefile), logstash-logback-encoder |
빌드는 Gradle Wrapper, 사내 Nexus Maven 저장소를 사용합니다. 로컬에서 의존성을 받으려면 VPN·사내망 접속이 필요할 수 있습니다.
로컬에서 띄워보기
준비물
- JDK 15
- Redis — docker compose up -d (프로젝트 루트 docker-compose.yml)
- PostgreSQL — 팀 DB 또는 로컬 PostGIS
- exlibs/ SSO JAR
- 파일 저장 경로 — userforge.storage.path, userloc.storage.path를 본인 환경에 맞게 수정
실행
./gradlew bootRun
기본 프로필은 local (application-local.yml 적용). 기본 포트는 8029입니다.
확인 항목URL 예시
| 헬스 | http://localhost:8029/user-loc-service/health |
| Swagger UI | http://localhost:8029/swagger-ui/index.html |
| OpenAPI JSON | http://localhost:8029/v3/api-docs |
| 인증 | POST http://localhost:8029/auth-service/auth |
IDE에서는 SvcAuthApplication 실행 + Active profile local이면 됩니다.
배포
Dockerfile은 UBI8 + JDK 15 베이스 이미지 위에 JAR을 올리고, ENV로 Spring profile을 주입합니다.
ENTRYPOINT ["sh", "-c", "java -Dspring.profiles.active=${ENV} -jar /home/gygo-svc3d-back-common-api-0.1.jar"]
프로필은 local, dev, prod, lxdev, lxprod 등 환경별 application-*.yml로 분리되어 있습니다.
개발하면서 느낀 포인트
1. 레거시 호환과 신규 REST의 공존
인증은 reqId 단일 POST, UserForge·user-loc은 RESTful path + HTTP method — 스타일이 다르지만 ResStd·UserIdResolver·예외 코드로 표면을 맞춥니다. 기존 포탈을 깨지 않으면서 3D 전용 기능을 붙이기 좋은 타협입니다.
2. 파일 + DB + 공간 타입
Shapefile은 “파일 시스템 문제”이면서 동시에 “DB geometry 문제”입니다. ZIP 해제, DBF 파싱, EWKT↔GeoJSON, 소유권 검증이 한 서비스 안에서 이어집니다. 이런 도메인은 MSA로 쪼개기보다 한 프로세스에서 트랜잭션·롤백을 명확히 하는 편이 유지보수에 유리한 경우가 많습니다.
3. 문서화
Swagger(SpringDoc) 외에 docs/api-spec.md처럼 운영포탈 API 정의서 양식을 보완한 Markdown 명세도 함께 관리합니다. docs/build_api_docx.py로 Word 정의서 생성까지 자동화할 수 있습니다.
4. 정적 분석
SpotBugs(NP_* 등 null 관련 패턴)와 SonarQube 연동이 Gradle에 포함되어 있습니다. SvcAuthApplication.main에는 CWE-489(Leftover Debug Code) 오탐을 설명하는 주석까지 — 보안 스캔과 실무를 같이 가져가는 흔적이 보입니다.
마치며
gygo-svc3d-back-common-api는 이름과 달리 “인증만 하는 서비스”가 아닙니다. GYGO 3D 생태계에서 반복적으로 필요한 인증·권한·사용자 공간데이터·나의 지역을 한 Spring Boot 앱에 모은 공통 백엔드 허브에 가깝습니다.
- 포탈 개발자에게는 reqId + ResStd라는 익숙한 계약
- 3D·지도 기능 개발자에게는 Shapefile·GeoJSON·PostGIS 파이프라인
- 운영자에게는 Redis·듀얼 DB·프로필 기반 배포
처음 코드베이스를 열었다면 AuthController → UserDatasetController → UserLocController 순으로 훑고, Swagger UI에서 실제 요청 형태를 확인하는 것을 추천합니다.
참고
- 프로젝트 README: README.md
- API 보완 명세: docs/api-spec.md
이 문서는 프로젝트 README·소스 코드·API 명세를 바탕으로 작성되었습니다. 운영 환경의 DB 접속 정보·JWT secret 등은 저장소에 커밋하지 않고 외부 설정으로 주입하는 것을 권장합니다.