# alist API Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다. ## 프로젝트 개요 - 그룹: `com.alist` - Java: `21` - Spring Boot: `3.5.10` - 포트: `8106` - 빌드 결과물: `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 기반 세션 관리와 쿠키 설정 - Swagger UI Basic 인증 보호 - DB 기반 허용 Origin 캐시를 사용하는 동적 CORS - TUS 업로드 초기화, 권한 검증, 상태 조회, 완료 처리, 취소 처리 - 파일 조회/다운로드 API - 공통 응답 래퍼 `ApiResponse` 및 `ApiResponseCode` 사용 ## 디렉터리 구조 ```text src/main/java/com/alist/api ├── common │ ├── modules/file # 공통 파일 업로드/다운로드 모듈 │ ├── response # ApiResponse, ApiResponseCode │ └── utils # 공통 유틸리티 ├── config │ ├── cache # CORS 허용 Origin 캐시 │ ├── exception # 전역 예외 처리 │ ├── filter # DynamicCorsFilter │ ├── jwt # JWT 인증 관련 구성 │ └── properties # 설정 프로퍼티 └── modules ├── auth # 인증/세션 관련 API ├── main # 루트 리다이렉트 ``` 리소스 파일은 아래 위치를 사용합니다. - 설정: `src/main/resources/application*.yaml` - Mapper XML: `src/main/resources/mapper/**/*.xml` - 로그 설정: `src/main/resources/logback-*.xml` ## 실행 방법 ### 빌드 ```bash ./gradlew bootJar ``` ### 로컬 실행 ```bash ./gradlew bootRun --args='--spring.profiles.active=local' ``` ### JAR 실행 ```bash java -jar build/libs/api.jar --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` ### 파일 업로드 - `file.upload.tus-endpoint` - `file.upload.public-base-url` - `file.upload.tmp-root` - `file.upload.final-root` - `file.upload.interrupt-seconds` - `file.upload.auth-cache.ttl-seconds` `pjt` 프로파일은 DB/Redis/JWT/Swagger 값을 환경변수로 주입받도록 작성되어 있습니다. ## 보안 구조 ### Swagger - 보호 경로: `/v3/api-docs/**`, `/swagger-ui/**`, `/swagger-ui.html` - 인증 방식: HTTP Basic - 계정 정보: `swagger.login.id`, `swagger.login.password` ### API - 기본 인증 방식: JWT Bearer - 세션 저장소: Redis - 세션 쿠키: `RedisSessionConfig`에서 도메인, Secure, SameSite 제어 ### 공개 경로 - `/` - `/actuator/health` - `/auth/**` - `/files/tusHook` 루트 `/` 요청은 `/swagger-ui/index.html`로 리다이렉트됩니다. ## CORS `DynamicCorsFilter`가 최우선 필터로 동작하며, 허용 Origin 목록은 `CorsAllowedOriginsCache`에서 조회합니다. - 허용된 Origin에만 `Access-Control-Allow-Origin` 설정 - Credential 허용 - `OPTIONS` preflight 요청은 `200 OK`로 즉시 응답 - DB를 직접 매 요청마다 조회하지 않고 캐시된 목록을 사용 ## 파일 업로드/다운로드 이 프로젝트는 대용량 업로드를 위해 TUS 서버(`tusd`)와 연동합니다. API는 업로드 메타데이터 관리, 업로드 권한 검증, 상태 저장, 완료/취소 처리를 담당합니다. ### 주요 업로드 엔드포인트 - `POST /files/uploadInit` - `GET /files/uploadAuth` - `POST /files/uploadStatus` - `POST /files/tusHook` - `POST /files/uploadCancel` ### 파일 조회 엔드포인트 - `GET /files/list/{fileMasterIdx}` - `GET /files/view/{fileUuid}` - `GET /files/download/{fileUuid}` ### 운영 메모 - TUS 업로드 엔드포인트: `https://file-alist.pjt.kr/tus/files/` - 업로드 임시 경로: `/srv/project/alist/uploads/tmp` - 업로드 최종 경로: `/srv/project/alist/uploads` - 정적 파일 도메인: `https://file-alist.pjt.kr` ## 주요 인증 엔드포인트 - `POST /auth/token` - `POST /auth/refresh` - `GET /auth/loginChecked` - `POST /auth/logout` - `POST /user/signup` ## API 예시 요청/응답 아래 예시는 실제 컨트롤러의 요청 필드와 `ApiResponse` 응답 구조를 기준으로 정리했습니다. ### 1. 토큰 발급 요청: ```http POST /auth/token Content-Type: application/json { "id": "test" } ``` 응답 예시: ```json { "data": { "id": null, "accessToken": "eyJhbGciOiJI..." }, "code": "CODE_2001", "message": "임시 토큰 정보 조회에 성공하였습니다." } ``` ### 2. 테스트 회원가입 요청: ```http POST /test/testSignup Content-Type: application/json { "id": "testuser01", "password": "pass1234" } ``` 응답 예시: ```json { "data": { "userIdx": 101, "id": "testuser01" }, "code": "CODE_2002", "message": "아이디 등록 되었습니다." } ``` 중복일 경우 예시: ```json { "data": { "userIdx": null, "id": null }, "code": "CODE_2004", "message": "중복된 아이디 정보 입니다." } ``` ### 3. 파일 업로드 초기화 요청: ```http POST /files/uploadInit Content-Type: application/json Cookie: ALIST_SESSION=... { "fileCategory": "notice", "folderPath": "/2026/03", "itemList": [ { "originName": "guide.pdf", "sizeBytes": 102400, "contentType": "application/pdf" } ] } ``` 응답 예시: ```json { "data": { "fileMasterIdx": 55, "tusEndpoint": "https://file-alist.pjt.kr/tus/files/", "itemList": [ { "fileSeq": 1, "fileUuid": "2f5f3ef1-8a4e-4b2d-84da-1c1111111111", "uploadToken": "upload-token-sample", "originName": "guide.pdf", "sizeBytes": 102400, "contentType": "application/pdf" } ] }, "code": "CODE_200", "message": "성공" } ``` ### 4. 업로드 상태 조회 요청: ```http POST /files/uploadStatus Content-Type: application/json { "fileUuid": "2f5f3ef1-8a4e-4b2d-84da-1c1111111111" } ``` 응답 예시: ```json { "data": { "fileUuid": "2f5f3ef1-8a4e-4b2d-84da-1c1111111111", "status": "UPLOADING", "uploadedBytes": 51200, "totalBytes": 102400, "percent": 50, "updatedAt": "2026-03-11T09:30:00" }, "code": "CODE_200", "message": "성공" } ``` 조회 결과가 없을 경우 예시: ```json { "data": { "fileUuid": null, "status": null, "uploadedBytes": null, "totalBytes": null, "percent": null, "updatedAt": null }, "code": "CODE_2003", "message": "조회된 정보가 없습니다." } ``` ## Actuator 외부 노출 대상은 아래와 같습니다. - `health` - `info` - `metrics` 헬스체크 기본 경로: - `GET /actuator/health` ## 응답 규칙 모든 API 응답은 `ApiResponse` 래퍼를 사용하며, 상태/메시지는 `ApiResponseCode` enum으로 관리합니다. 자주 사용하는 코드 예시는 아래와 같습니다. | 코드 | HTTP Status | 의미 | | --- | --- | --- | | `CODE_200` | `200 OK` | 일반 성공 | | `CODE_204` | `204 No Contnet` | 일반 성공 | | `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` | 서버 오류 | ## 배포 관련 - 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` ## 참고 - Swagger 로컬 접속: [http://localhost:8106/swagger-ui.html](http://localhost:8106/swagger-ui.html) - 운영 환경에서는 `application-pjt.yaml`의 환경변수 주입 방식 사용을 권장합니다. ## 라이선스 Proprietary