# alist API Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다. ## 프로젝트 개요 - 그룹: `com.alist` - Java: `21` - Spring Boot: `3.5.10` - 기본 포트: `8106` - 실행 진입점: `src/main/java/com/alist/api/ApiApplication.java` - 빌드 결과물: `build/libs/api.jar` ## 기술 스택 - Spring Web - Spring Security - JWT (`jjwt 0.11.5`) - Spring Session + Redis - MyBatis (`mapper/**/*.xml`) - MariaDB - Swagger / OpenAPI (`springdoc-openapi 2.8.0`) - Validation - Actuator - Lombok - log4jdbc ## 주요 기능 - 사용자/관리자 JWT 발급 및 검증 - Redis 기반 SSO 세션 관리와 쿠키 설정 - Swagger UI Basic 인증 보호 - DB 기반 허용 Origin 캐시를 사용하는 동적 CORS - TUS 기반 대용량 파일 업로드 초기화, 권한 검증, 상태 조회, hook 처리, 취소 처리 - DB 기록 없는 단순 파일 업로드와 uploadPath 반환 - SunEditor 이미지 업로드와 file-domain URL 반환 - 파일 view/download API - 공통 응답 래퍼 `ApiResponse` 및 `ApiResponseCode` 사용 ## 디렉터리 구조 ```text src/main/java/com/alist/api ├── common │ ├── response # ApiResponse, ApiResponseCode │ └── utils # 공통 유틸리티 ├── config │ ├── cache # CORS 허용 Origin 캐시 │ ├── exception # 전역 예외 처리 │ ├── filter # DynamicCorsFilter │ ├── jwt # JWT 인증 관련 구성 │ ├── migration # 마이그레이션 DB 설정 │ └── properties # 설정 프로퍼티 └── modules ├── admin # 관리자 인증 API ├── auth # 사용자 인증/SSO API ├── file # 단순 업로드, SunEditor 업로드, path 기반 view/download ├── main # 루트 응답 ├── migration # 레거시 사용자 조회 ├── tusFile # TUS 업로드 DB 기록, hook, 상태, 파일 목록/view/download/delete └── user # 사용자 가입/마이그레이션 조회 ``` 리소스 파일은 아래 위치를 사용합니다. - 설정: `src/main/resources/application*.yaml` - Mapper XML: `src/main/resources/mapper/**/*.xml` - 로그 설정: `src/main/resources/logback-*.xml` - 상세 문서: `docs/*.md` ## 실행 방법 ### 빌드 ```bash ./gradlew bootJar ``` ### 로컬 실행 ```bash ./gradlew bootRun --args='--spring.profiles.active=local' ``` ### JAR 실행 ```bash java -jar build/libs/api.jar --spring.profiles.active=local ``` Windows: ```powershell .\gradlew.bat bootRun --args='--spring.profiles.active=local' ``` ## 프로파일 | 프로파일 | 설명 | 설정 파일 | | --- | --- | --- | | `local` | 로컬 개발 환경 | `src/main/resources/application-local.yaml` | | `pjt` | 프로젝트 개발 서버 환경 | `src/main/resources/application-pjt.yaml` | 공통 설정은 `src/main/resources/application.yaml`에 있습니다. ## 필수 설정 항목 ### 데이터 저장소 - `spring.datasource.*` - `spring.data.redis.*` - `spring.session.*` ### 인증/보안 - `jwt.secret` - `jwt.access-token-validity-seconds` - `jwt.refresh-token-validity-seconds` - `cookie.secure` - `cookie.domain` - `cookie.name` - `cookie.same-site` - `swagger.login.id` - `swagger.login.password` ### TUS 업로드 - `tus-file.upload.tus-endpoint` - `tus-file.upload.public-base-url` - `tus-file.upload.tmp-root` - `tus-file.upload.final-root` - `tus-file.upload.interrupt-seconds` - `tus-file.upload.auth-cache.ttl-seconds` ### 단순 업로드 / 에디터 이미지 - `file.upload.root-path` - `file.upload.view.file-domain` - `file.upload.max-size` - `file.upload.allowed-extensions` - `file.upload.types.*` `pjt` 프로파일은 DB/Redis/JWT/Swagger 값을 환경변수로 주입받도록 작성되어 있습니다. ## 보안 구조 ### Swagger - 보호 경로: `/v3/api-docs/**`, `/swagger-ui/**`, `/swagger-ui.html` - 인증 방식: HTTP Basic - 계정 정보: `swagger.login.id`, `swagger.login.password` ### Admin API - `/admin/**` 는 별도 SecurityFilterChain을 사용합니다. - `/admin/auth/**` 는 공개하고, 그 외 `/admin/**` 는 `ADMIN` 권한을 요구합니다. - `GET /admin/auth/loginChecked` 는 토큰 재발급 없이 현재 관리자 로그인 상태만 확인합니다. ### API - 기본 인증 방식: JWT Bearer 또는 HttpOnly 쿠키 fallback - 세션 저장소: Redis - 쿠키 속성: `cookie.*` 설정으로 제어 ### 공개 경로 - `/` - `/actuator/health` - `/sso/**` - `/auth/**` - `/user/signup` - `/user/migrationUserList` - `/tusFiles/uploadAuth` - `/tusFiles/tusHook` TUS 업로드 토큰은 일반 access token이 아니므로 `/tusFiles/uploadAuth`, `/tusFiles/tusHook` 은 JWT 필터 제외 경로에도 포함되어야 합니다. ## CORS `DynamicCorsFilter`가 최우선 필터로 동작하며, 허용 Origin 목록은 `CorsAllowedOriginsCache`에서 조회합니다. - 허용된 Origin에만 `Access-Control-Allow-Origin` 설정 - Credential 허용 - `OPTIONS` preflight 요청은 `200 OK`로 즉시 응답 - DB를 직접 매 요청마다 조회하지 않고 캐시된 목록을 사용 file-domain nginx 의 TUS 업로드 경로는 별도 `map $http_origin $cors_allow_origin` 설정으로 허용 Origin을 제한합니다. ## 파일 업로드 파일 업로드는 두 흐름으로 분리되어 있습니다. ### 단순 업로드 DB에 기록하지 않고 파일만 저장한 뒤 업무 테이블에 저장하기 좋은 값을 반환합니다. - `POST /files/upload` - `POST /admin/files/upload` - `GET /files/view?path=/uploads/...` - `GET /admin/files/view?path=/uploads/...` - `GET /files/download?path=/uploads/...` - `GET /admin/files/download?path=/uploads/...` 응답 데이터 예시: ```json { "uploadPath": "/uploads/notice/2026/05/08/abc.png", "originalFileName": "sample.png", "storedFileName": "abc.png", "fileExtension": "png", "contentType": "image/png", "fileSize": 12345, "width": 800, "height": 600 } ``` ### SunEditor 이미지 업로드 SunEditor 업로드는 API로 저장하되, 에디터 본문에는 token이 필요 없는 file-domain URL을 저장합니다. - `POST /files/suneditor/upload` - `POST /admin/files/suneditor/upload` 응답 예시: ```json { "result": [ { "url": "https://file-alist.pjt.kr/uploads/editor/2026/05/08/abc.png", "name": "sample.png", "size": 12345 } ] } ``` ### TUS 업로드 대용량 업로드는 tusd와 연동하며 API는 DB 기록, 토큰 발급, 권한 검증, hook 반영을 담당합니다. - `POST /tusFiles/uploadInit` - `GET /tusFiles/uploadAuth` - `POST /tusFiles/uploadStatus` - `POST /tusFiles/tusHook` - `POST /tusFiles/uploadCancel` - `GET /tusFiles/list/{fileMasterIdx}` - `GET /tusFiles/view/{fileUuid}` - `GET /tusFiles/download/{fileUuid}` - `POST /tusFiles/delete` 운영 TUS 엔드포인트: ```text https://file-alist.pjt.kr/tus/files/ ``` ## file-domain 운영 메모 - 업로드 최종 경로: `/srv/project/alist/uploads` - tusd 임시 경로: `/srv/project/alist/uploads/tmp` - 파일 도메인: `https://file-alist.pjt.kr` - nginx `/uploads/` 는 `/srv/project/alist/uploads/` 를 정적 파일로 제공합니다. - nginx `/uploads/tmp/` 는 임시 파일 노출 방지를 위해 404 처리합니다. - nginx `/tus/files/` 는 tusd로 프록시하고 `auth_request /_upload_auth` 로 `/tusFiles/uploadAuth` 를 호출합니다. ## 주요 인증 엔드포인트 - `POST /auth/token` - `POST /auth/access` - `POST /auth/refresh` - `POST /auth/apiKeyLogin` - `GET /sso/loginChecked` - `POST /sso/login` - `POST /sso/exchange` - `POST /sso/logout` - `POST /admin/auth/login` - `POST /admin/auth/refresh` - `GET /admin/auth/loginChecked` - `POST /admin/auth/logout` - `POST /user/signup` ## Actuator 외부 노출 대상은 아래와 같습니다. - `health` - `info` - `metrics` 헬스체크 기본 경로: - `GET /actuator/health` ## 응답 규칙 모든 API 응답은 `ApiResponse` 래퍼를 우선 사용하며, 상태/메시지는 `ApiResponseCode` enum으로 관리합니다. 자주 사용하는 코드 예시는 아래와 같습니다. | 코드 | HTTP Status | 의미 | | --- | --- | --- | | `CODE_200` | `200 OK` | 일반 성공 | | `CODE_204` | `204 No Content` | 일반 성공 | | `CODE_2001` | `200 OK` | 단건 조회 성공 | | `CODE_2002` | `201 Created` | 등록 성공 | | `CODE_2003` | `200 OK` | 조회 결과 없음 | | `CODE_2004` | `409 Conflict` | 중복 데이터 | | `CODE_4001` | `400 Bad Request` | 입력값/바인딩 오류 | | `CODE_4003` | `400 Bad Request` | 필수 파라미터 누락 | | `CODE_401` | `401 Unauthorized` | 인증 필요 | | `CODE_403` | `403 Forbidden` | 권한 없음 | | `CODE_500` | `500 Internal Server Error` | 서버 오류 | 파일 binary view/download 응답은 `ResponseEntity` 로 직접 내려줄 수 있습니다. ## 배포 관련 - Dockerfile: `Dockerfile` - Jenkins 파이프라인: `Jenkinsfile.pjt` - 배포 스크립트: `deploy/` - 개발 서버 API 도메인: `https://api-alist.pjt.kr` - 파일 도메인: `https://file-alist.pjt.kr` - Swagger: `https://api-alist.pjt.kr/swagger-ui/index.html` ## 상세 문서 - [프로젝트 개요](docs/project-overview.md) - [보안 및 응답 규칙](docs/security-and-response.md) - [설정 및 실행 가이드](docs/runtime-config.md) - [검증 및 체크리스트](docs/verification-checklist.md) - [현재 코드베이스 메모](docs/codebase-notes.md) ## 라이선스 Proprietary