admin/front 분리
This commit is contained in:
@@ -1,336 +1,90 @@
|
||||
# alist API
|
||||
|
||||
Spring Boot 3 기반의 `alist` 백엔드 API 서버입니다.
|
||||
Gradle 기반 Spring Boot 멀티모듈 API 프로젝트입니다. 하나의 저장소에서 core 공통 기능과 admin/front 실행 서버를 함께 관리합니다.
|
||||
|
||||
## 프로젝트 개요
|
||||
## 모듈
|
||||
|
||||
- 그룹: `com.alist`
|
||||
- Java: `21`
|
||||
- Spring Boot: `3.5.10`
|
||||
- 기본 포트: `8106`
|
||||
- 실행 진입점: `src/main/java/com/alist/api/ApiApplication.java`
|
||||
- 빌드 결과물: `build/libs/api.jar`
|
||||
```text
|
||||
01-api-core 공통 인프라, 공통 기능, 업무 모듈 라이브러리
|
||||
02-api-admin 관리자 API 실행 서버
|
||||
03-api-front 사용자 API 실행 서버
|
||||
```
|
||||
|
||||
- `01-api-core`는 단독 실행하지 않습니다.
|
||||
- `02-api-admin`은 `api-admin.jar`를 생성합니다.
|
||||
- `03-api-front`는 `api-front.jar`를 생성합니다.
|
||||
- admin/front는 각각 core에 의존하며, 서로의 Controller를 포함하지 않습니다.
|
||||
|
||||
## 처음 보는 사람을 위한 구조
|
||||
|
||||
```text
|
||||
HTTP 요청
|
||||
-> admin/front Controller
|
||||
-> admin/front 업무 Service
|
||||
-> core standard 또는 bespoke Service
|
||||
-> Mapper -> Mapper XML -> DB
|
||||
```
|
||||
|
||||
- `admin`과 `front`는 각각 실행·배포되는 API 서버입니다.
|
||||
- `core`는 실행하지 않는 공유 라이브러리이며, 공통 기능과 DB 접근 코드를 둡니다.
|
||||
- 단일 테이블 SQL은 `standard`, 여러 테이블 JOIN이나 복합 SQL은 `bespoke`에 둡니다.
|
||||
- Controller는 HTTP만, admin/front Service는 업무 흐름만, core는 데이터 접근만 담당합니다.
|
||||
|
||||
처음 참여했다면 [구조 한눈에 보기](docs/architecture-at-a-glance.md) -> [Core 모듈 설계](docs/core-module-design.md) -> [코드 컨벤션](docs/code-conventions.md) 순서로 읽습니다.
|
||||
|
||||
## 빌드와 실행
|
||||
|
||||
```bash
|
||||
./gradlew :02-api-admin:bootJar
|
||||
./gradlew :03-api-front:bootJar
|
||||
```
|
||||
|
||||
빌드 결과:
|
||||
|
||||
```text
|
||||
02-api-admin/build/libs/api-admin.jar
|
||||
03-api-front/build/libs/api-front.jar
|
||||
```
|
||||
|
||||
로컬 실행:
|
||||
|
||||
```bash
|
||||
./gradlew :02-api-admin:bootRun --args='--spring.profiles.active=local'
|
||||
./gradlew :03-api-front:bootRun --args='--spring.profiles.active=local'
|
||||
```
|
||||
|
||||
Windows에서는 `./gradlew` 대신 `./gradlew.bat`를 사용합니다.
|
||||
|
||||
## 패키지 기준
|
||||
|
||||
```text
|
||||
com.alist.api.core
|
||||
com.alist.api.admin
|
||||
com.alist.api.front
|
||||
```
|
||||
|
||||
- `core.common`: JWT, 예외, 공통 응답, 유틸처럼 시스템 전반에서 사용하는 기능
|
||||
- `core.config`: DataSource, MyBatis, 공통 인프라 설정
|
||||
- `core.modules.standard`: 단일 테이블의 표준 조회·등록·수정·삭제
|
||||
- `core.modules.bespoke`: 여러 테이블 JOIN, 집계, 복합 SQL 데이터 접근
|
||||
- `admin`/`front`: Controller, Form, VO, 각 서버의 Security/OpenAPI 설정
|
||||
|
||||
상세 기준은 [Core 모듈 설계](docs/core-module-design.md)를 참고합니다.
|
||||
|
||||
## 기술 스택
|
||||
|
||||
- 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
|
||||
- Java 21, Spring Boot 3.5.10, Gradle
|
||||
- MyBatis, MariaDB, SQL Server 마이그레이션 데이터소스
|
||||
- Spring Security, JWT, Redis
|
||||
- Swagger / OpenAPI, Actuator, Lombok, Validation, log4jdbc
|
||||
|
||||
## 주요 기능
|
||||
|
||||
- 사용자/관리자 JWT 발급 및 검증
|
||||
- Redis 기반 SSO 세션 관리와 쿠키 설정
|
||||
- Swagger UI Basic 인증 보호
|
||||
- DB 기반 허용 Origin 캐시를 사용하는 동적 CORS
|
||||
- TUS 기반 대용량 파일 업로드 초기화, 권한 검증, 상태 조회, hook 처리, 취소 처리
|
||||
- DB 기록 없는 단순 파일 업로드와 uploadPath 반환
|
||||
- SunEditor 이미지 업로드와 file-domain URL 반환
|
||||
- 파일 view/download API
|
||||
- 공통 응답 래퍼 `ApiResponse<T>` 및 `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 # 관리자 인증/회원/스케줄/SSO 클라이언트 관리 API
|
||||
├── cors # DB 기반 허용 Origin 관리와 캐시 갱신 API
|
||||
├── file # 단순 업로드, SunEditor 업로드, path 기반 view/download
|
||||
├── front # 사용자 인증/SSO API와 사용자 관리 API
|
||||
├── main # 루트 응답
|
||||
├── migration # 레거시 사용자 조회
|
||||
├── tusFile # TUS 업로드 DB 기록, hook, 상태, 파일 목록/view/download/delete
|
||||
```
|
||||
|
||||
리소스 파일은 아래 위치를 사용합니다.
|
||||
|
||||
- 설정: `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/user/add` 는 공개하고, 그 외 `/admin/**` 는 `ADMIN` 권한을 요구합니다.
|
||||
- `GET /admin/auth/loginChecked` 는 토큰 재발급 없이 현재 관리자 로그인 상태만 확인합니다.
|
||||
|
||||
### API
|
||||
|
||||
- 기본 인증 방식: JWT Bearer 또는 HttpOnly 쿠키 fallback
|
||||
- 세션 저장소: Redis
|
||||
- 쿠키 속성: `cookie.*` 설정으로 제어
|
||||
|
||||
### 공개 경로
|
||||
|
||||
- `/`
|
||||
- `/actuator/health`
|
||||
- `/sso/**`
|
||||
- `/auth/**`
|
||||
- `/user/add`
|
||||
- `/user/migration/list`
|
||||
- `/tus/file/upload/auth`
|
||||
- `/tus/file/hook`
|
||||
- `/file/**`
|
||||
|
||||
TUS 업로드 토큰은 일반 access token이 아니므로 `/tus/file/upload/auth`, `/tus/file/hook` 은 file-domain nginx `auth_request` 설정과 Spring Security 공개 경로를 함께 맞춰야 합니다.
|
||||
|
||||
## CORS
|
||||
|
||||
`DynamicCorsFilter`가 최우선 필터로 동작하며, 허용 Origin 목록은 `CorsCache`에서 조회합니다.
|
||||
|
||||
- 허용된 Origin에만 `Access-Control-Allow-Origin` 설정
|
||||
- Credential 허용
|
||||
- `OPTIONS` preflight 요청은 `200 OK`로 즉시 응답
|
||||
- DB를 직접 매 요청마다 조회하지 않고 캐시된 목록을 사용
|
||||
|
||||
file-domain nginx 의 TUS 업로드 경로는 별도 `map $http_origin $cors_allow_origin` 설정으로 허용 Origin을 제한합니다.
|
||||
|
||||
## 파일 업로드
|
||||
|
||||
파일 업로드는 두 흐름으로 분리되어 있습니다.
|
||||
|
||||
### 단순 업로드
|
||||
|
||||
DB에 기록하지 않고 파일만 저장한 뒤 업무 테이블에 저장하기 좋은 값을 반환합니다.
|
||||
|
||||
- `POST /file/upload`
|
||||
- `GET /file/view?path=/uploads/...`
|
||||
- `GET /file/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 /file/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 /tus/file/upload/init`
|
||||
- `GET /tus/file/upload/auth`
|
||||
- `POST /tus/file/upload/status`
|
||||
- `POST /tus/file/hook`
|
||||
- `POST /tus/file/upload/cancel`
|
||||
- `GET /tus/file/list/{fileMasterIdx}`
|
||||
- `GET /tus/file/view/{fileUuid}`
|
||||
- `GET /tus/file/download/{fileUuid}`
|
||||
- `POST /tus/file/delete`
|
||||
|
||||
운영 TUS 엔드포인트:
|
||||
|
||||
```text
|
||||
https://file-alist.pjt.kr/tus/file/
|
||||
```
|
||||
|
||||
## 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/file/` 는 tusd로 프록시하고 `auth_request /_upload_auth` 로 `/tus/file/upload/auth` 를 호출합니다.
|
||||
|
||||
## 주요 인증 엔드포인트
|
||||
|
||||
- `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/add`
|
||||
- `POST /user/migration/list`
|
||||
|
||||
## Actuator
|
||||
|
||||
외부 노출 대상은 아래와 같습니다.
|
||||
|
||||
- `health`
|
||||
- `info`
|
||||
- `metrics`
|
||||
|
||||
헬스체크 기본 경로:
|
||||
|
||||
- `GET /actuator/health`
|
||||
|
||||
## 응답 규칙
|
||||
|
||||
모든 API 응답은 `ApiResponse<T>` 래퍼를 우선 사용하며, 상태/메시지는 `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<Resource>` 로 직접 내려줄 수 있습니다.
|
||||
|
||||
## 배포 관련
|
||||
|
||||
- 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/architecture-at-a-glance.md)
|
||||
- [Core 모듈 설계](docs/core-module-design.md)
|
||||
- [코드 컨벤션](docs/code-conventions.md)
|
||||
- [보안 및 응답 규칙](docs/security-and-response.md)
|
||||
- [설정 및 실행 가이드](docs/runtime-config.md)
|
||||
- [검증 및 체크리스트](docs/verification-checklist.md)
|
||||
- [현재 코드베이스 메모](docs/codebase-notes.md)
|
||||
|
||||
## 라이선스
|
||||
|
||||
Proprietary
|
||||
|
||||
Reference in New Issue
Block a user