[api] 파일업로드, tus파일 주소변경, md 파일 변경

This commit is contained in:
2026-05-08 17:21:19 +09:00
parent 0fc91fddac
commit 13e41f6e3c
23 changed files with 981 additions and 268 deletions
+133 -194
View File
@@ -1,4 +1,4 @@
# alist API
# alist API
Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다.
@@ -7,7 +7,8 @@ Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다.
- 그룹: `com.alist`
- Java: `21`
- Spring Boot: `3.5.10`
- 포트: `8106`
- 기본 포트: `8106`
- 실행 진입점: `src/main/java/com/alist/api/ApiApplication.java`
- 빌드 결과물: `build/libs/api.jar`
## 기술 스택
@@ -26,12 +27,14 @@ Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다.
## 주요 기능
- JWT 발급 및 검증
- Redis 기반 세션 관리와 쿠키 설정
- 사용자/관리자 JWT 발급 및 검증
- Redis 기반 SSO 세션 관리와 쿠키 설정
- Swagger UI Basic 인증 보호
- DB 기반 허용 Origin 캐시를 사용하는 동적 CORS
- TUS 업로드 초기화, 권한 검증, 상태 조회, 완료 처리, 취소 처리
- 파일 조회/다운로드 API
- TUS 기반 대용량 파일 업로드 초기화, 권한 검증, 상태 조회, hook 처리, 취소 처리
- DB 기록 없는 단순 파일 업로드와 uploadPath 반환
- SunEditor 이미지 업로드와 file-domain URL 반환
- 파일 view/download API
- 공통 응답 래퍼 `ApiResponse<T>``ApiResponseCode` 사용
## 디렉터리 구조
@@ -39,7 +42,6 @@ Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다.
```text
src/main/java/com/alist/api
├── common
│ ├── modules/file # 공통 파일 업로드/다운로드 모듈
│ ├── response # ApiResponse, ApiResponseCode
│ └── utils # 공통 유틸리티
├── config
@@ -47,10 +49,16 @@ src/main/java/com/alist/api
│ ├── exception # 전역 예외 처리
│ ├── filter # DynamicCorsFilter
│ ├── jwt # JWT 인증 관련 구성
│ ├── migration # 마이그레이션 DB 설정
│ └── properties # 설정 프로퍼티
└── modules
├── auth # 인증/세션 관련 API
├── main # 루트 리다이렉트
├── admin # 관리자 인증 API
├── auth # 사용자 인증/SSO API
├── file # 단순 업로드, SunEditor 업로드, path 기반 view/download
├── main # 루트 응답
├── migration # 레거시 사용자 조회
├── tusFile # TUS 업로드 DB 기록, hook, 상태, 파일 목록/view/download/delete
└── user # 사용자 가입/마이그레이션 조회
```
리소스 파일은 아래 위치를 사용합니다.
@@ -58,6 +66,7 @@ src/main/java/com/alist/api
- 설정: `src/main/resources/application*.yaml`
- Mapper XML: `src/main/resources/mapper/**/*.xml`
- 로그 설정: `src/main/resources/logback-*.xml`
- 상세 문서: `docs/*.md`
## 실행 방법
@@ -79,6 +88,12 @@ src/main/java/com/alist/api
java -jar build/libs/api.jar --spring.profiles.active=local
```
Windows:
```powershell
.\gradlew.bat bootRun --args='--spring.profiles.active=local'
```
## 프로파일
| 프로파일 | 설명 | 설정 파일 |
@@ -90,8 +105,6 @@ java -jar build/libs/api.jar --spring.profiles.active=local
## 필수 설정 항목
실행 전 아래 설정들이 환경에 맞게 준비되어 있어야 합니다.
### 데이터 저장소
- `spring.datasource.*`
@@ -110,14 +123,22 @@ java -jar build/libs/api.jar --spring.profiles.active=local
- `swagger.login.id`
- `swagger.login.password`
### 파일 업로드
### TUS 업로드
- `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`
- `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 값을 환경변수로 주입받도록 작성되어 있습니다.
@@ -129,20 +150,30 @@ java -jar build/libs/api.jar --spring.profiles.active=local
- 인증 방식: HTTP Basic
- 계정 정보: `swagger.login.id`, `swagger.login.password`
### Admin API
- `/admin/**` 는 별도 SecurityFilterChain을 사용합니다.
- `/admin/auth/**` 는 공개하고, 그 외 `/admin/**``ADMIN` 권한을 요구합니다.
- `GET /admin/auth/loginChecked` 는 토큰 재발급 없이 현재 관리자 로그인 상태만 확인합니다.
### API
- 기본 인증 방식: JWT Bearer
- 기본 인증 방식: JWT Bearer 또는 HttpOnly 쿠키 fallback
- 세션 저장소: Redis
- 세션 쿠키: `RedisSessionConfig`에서 도메인, Secure, SameSite 제어
- 쿠키 속성: `cookie.*` 설정으로 제어
### 공개 경로
- `/`
- `/actuator/health`
- `/sso/**`
- `/auth/**`
- `/files/tusHook`
- `/user/signup`
- `/user/migrationUserList`
- `/tusFiles/uploadAuth`
- `/tusFiles/tusHook`
루트 `/` 요청은 `/swagger-ui/index.html`로 리다이렉트됩니다.
TUS 업로드 토큰은 일반 access token이 아니므로 `/tusFiles/uploadAuth`, `/tusFiles/tusHook` 은 JWT 필터 제외 경로에도 포함되어야 합니다.
## CORS
@@ -153,200 +184,103 @@ java -jar build/libs/api.jar --spring.profiles.active=local
- `OPTIONS` preflight 요청은 `200 OK`로 즉시 응답
- DB를 직접 매 요청마다 조회하지 않고 캐시된 목록을 사용
## 파일 업로드/다운로드
file-domain nginx 의 TUS 업로드 경로는 별도 `map $http_origin $cors_allow_origin` 설정으로 허용 Origin을 제한합니다.
이 프로젝트는 대용량 업로드를 위해 TUS 서버(`tusd`)와 연동합니다. API는 업로드 메타데이터 관리, 업로드 권한 검증, 상태 저장, 완료/취소 처리를 담당합니다.
## 파일 업로드
### 주요 업로드 엔드포인트
파일 업로드는 두 흐름으로 분리되어 있습니다.
- `POST /files/uploadInit`
- `GET /files/uploadAuth`
- `POST /files/uploadStatus`
- `POST /files/tusHook`
- `POST /files/uploadCancel`
### 단순 업로드
### 파일 조회 엔드포인트
DB에 기록하지 않고 파일만 저장한 뒤 업무 테이블에 저장하기 좋은 값을 반환합니다.
- `GET /files/list/{fileMasterIdx}`
- `GET /files/view/{fileUuid}`
- `GET /files/download/{fileUuid}`
- `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/...`
### 운영 메모
- 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<T>` 응답 구조를 기준으로 정리했습니다.
### 1. 토큰 발급
요청:
```http
POST /auth/token
Content-Type: application/json
응답 데이터 예시:
```json
{
"id": "test"
"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
{
"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": [
"result": [
{
"originName": "guide.pdf",
"sizeBytes": 102400,
"contentType": "application/pdf"
"url": "https://file-alist.pjt.kr/uploads/editor/2026/05/08/abc.png",
"name": "sample.png",
"size": 12345
}
]
}
```
응답 예시:
### TUS 업로드
```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": "성공"
}
대용량 업로드는 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/
```
### 4. 업로드 상태 조회
## 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` 를 호출합니다.
```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": "조회된 정보가 없습니다."
}
```
- `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
@@ -362,14 +296,14 @@ Content-Type: application/json
## 응답 규칙
모든 API 응답은 `ApiResponse<T>` 래퍼를 사용하며, 상태/메시지는 `ApiResponseCode` enum으로 관리합니다.
모든 API 응답은 `ApiResponse<T>` 래퍼를 우선 사용하며, 상태/메시지는 `ApiResponseCode` enum으로 관리합니다.
자주 사용하는 코드 예시는 아래와 같습니다.
| 코드 | HTTP Status | 의미 |
| --- | --- | --- |
| `CODE_200` | `200 OK` | 일반 성공 |
| `CODE_204` | `204 No Contnet` | 일반 성공 |
| `CODE_204` | `204 No Content` | 일반 성공 |
| `CODE_2001` | `200 OK` | 단건 조회 성공 |
| `CODE_2002` | `201 Created` | 등록 성공 |
| `CODE_2003` | `200 OK` | 조회 결과 없음 |
@@ -380,6 +314,8 @@ Content-Type: application/json
| `CODE_403` | `403 Forbidden` | 권한 없음 |
| `CODE_500` | `500 Internal Server Error` | 서버 오류 |
파일 binary view/download 응답은 `ResponseEntity<Resource>` 로 직접 내려줄 수 있습니다.
## 배포 관련
- Dockerfile: `Dockerfile`
@@ -389,10 +325,13 @@ Content-Type: application/json
- 파일 도메인: `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`의 환경변수 주입 방식 사용을 권장합니다.
- [프로젝트 개요](docs/project-overview.md)
- [보안 및 응답 규칙](docs/security-and-response.md)
- [설정 및 실행 가이드](docs/runtime-config.md)
- [검증 및 체크리스트](docs/verification-checklist.md)
- [현재 코드베이스 메모](docs/codebase-notes.md)
## 라이선스