7.5 KiB
7.5 KiB
AGENTS.md - alist API 프로젝트
Claude 작업 규칙 (중요!)
코드 수정 시 반드시 따를 것
- 절대로 바로 파일을 수정하지 말 것
- 먼저 수정 방향과 계획을 설명
- 긴 소스 코드를 보여주기 전에 먼저 물어보기
- "코드 보여드릴까요?" 또는 "직접 수정하시겠어요?"
- 사용자가 원하면 코드 보여주기 (사용자가 직접 수정할 수도 있도록)
- 파일 작성/수정은 사용자가 요청할 때만
작업 순서 예시
1. "CORS 설정을 yml로 분리하겠습니다."
2. "수정 내용:"
- CorsProperties.java 생성 필요
- CorsConfig.java 수정 필요
- application-local.yaml 수정 필요
3. "코드 보여드릴까요? 아니면 직접 수정하시겠어요?"
4. (사용자가 "보여줘"라고 하면) 코드 보여주기
5. (사용자가 "작성해줘"라고 하면) 파일 수정 진행
주의사항
- 짧은 설명(수정 위치, 수정 방향)은 바로 보여줘도 됨
- 전체 메서드/클래스 같은 긴 코드는 반드시 물어본 후 보여주기
- 화면이 너무 길어지는 것 방지
프로젝트 개요
- 프로젝트명: alist API
- 그룹: com.alist
- 포트: 8106
- 빌드 결과물:
api.jar
기술 스택
- Java: 21
- Framework: Spring Boot 3.5.10
- 빌드 도구: Gradle
- DB: MariaDB
- ORM: MyBatis (mapper XML:
classpath:mapper/**/*.xml) - 인증: JWT (jjwt 0.11.5) + Spring Security
- API 문서: Swagger (springdoc-openapi 2.6.0)
- 기타: Lombok, Validation, Actuator, log4jdbc
패키지 구조
com.alist.api
├── common
│ ├── response/ # ApiResponse, ApiResponseCode
│ └── utils/ # 공통 유틸리티
├── config
│ ├── jwt/ # JWT 필터, 핸들러, Provider
│ ├── exception/ # GlobalExceptionHandler
│ ├── properties/ # JwtProperties 등
│ ├── SecurityConfig.java
│ └── OpenApiConfig.java
└── modules
└── {도메인}/ # Controller, Service, Mapper, DTO
프로파일
| 프로파일 | 설명 |
|---|---|
local |
로컬 개발 환경 |
pjt |
프로젝트(개발) 환경 |
보안 구조
- Swagger:
/v3/api-docs/**,/swagger-ui/**→ HTTP Basic 인증 (InMemory) - API: JWT Bearer 토큰 인증 (Stateless)
- 공개 경로:
/,/actuator/health,/auth/**,/api/user/signup
응답 코드 규칙
ApiResponseCode enum으로 관리. 주요 코드:
| 코드 | 메시지 | HTTP Status | 용도 |
|---|---|---|---|
CODE_200 |
성공 | 200 OK | 일반 성공 |
CODE_400 |
잘못된 요청 | 400 Bad Request | 일반 클라이언트 오류 |
CODE_401 |
인증 필요 합니다. | 401 Unauthorized | 인증 없음 |
CODE_403 |
접근 권한 필요 합니다. | 403 Forbidden | 권한 없음 |
CODE_404 |
페이지를 찾을 수 없습니다. | 404 Not Found | 리소스 없음 |
CODE_405 |
잘못된 요청입니다. 요청 방식을 확인해 주세요. | 405 Method Not Allowed | 메서드 불일치 |
CODE_500 |
요청을 처리하는 중 오류가 발생했습니다. | 500 Internal Server Error | 서버 오류 |
CODE_2001 |
{0} 정보 조회에 성공하였습니다. | 200 OK | 단건 조회 성공 |
CODE_2002 |
{0} 등록 되었습니다. | 201 Created | 등록 성공 |
CODE_2003 |
조회된 정보가 없습니다. | 200 OK | 조회 결과 없음 |
CODE_2004 |
중복된 {0} 정보 입니다. | 409 Conflict | 중복 데이터 |
CODE_4001 |
입력값을 확인해주세요. | 400 Bad Request | @Valid / 바인딩 / 타입오류 / JSON 파싱 실패 |
CODE_4003 |
필수 요청 파라미터가 누락되었습니다. | 400 Bad Request | 필수 파라미터 누락 |
{0}자리에 대상명 삽입 (예:CODE_2001→ "회원 정보 조회에 성공하였습니다.")
빌드 및 실행
# 빌드
./gradlew bootJar
# 로컬 실행
./gradlew bootRun --args='--spring.profiles.active=local'
# JAR 실행
java -jar build/libs/api.jar --spring.profiles.active=local
Swagger 접속
- URL:
http://localhost:8106/swagger-ui.html - 인증:
swagger.login.id/swagger.login.password(환경별 yaml에 설정)
코드 작성 규칙
- 응답은
ApiResponse<T>래퍼 사용 - 응답 코드는
ApiResponseCodeenum 사용 - MyBatis Mapper XML은
src/main/resources/mapper/하위에 작성 - 카멜케이스 자동 변환 활성화 (
map-underscore-to-camel-case: true) - 새 모듈 추가 시:
modules/{moduleName}/하위에 Controller, Service, Mapper, dto/, vo/ 구조로 생성 - Mapper XML은
resources/mapper/{moduleName}/에 위치
MyBatis 규칙
- Mapper XML 위치:
src/main/resources/mapper/**/*.xml map-underscore-to-camel-case: true설정 → DB 컬럼user_idx→ Java 필드userIdx자동 매핑- Mapper 인터페이스와 XML의 namespace, id 반드시 일치시킬 것
- VO: DB 조회 결과 매핑용 / DTO: 서비스 레이어 간 데이터 전달용 / Form: 컨트롤러 입력 검증용
CI/CD
- Jenkins:
Jenkinsfile.pjt - Docker:
Dockerfile - 배포 스크립트:
deploy/디렉토리
개발 서버 (pjt)
도메인
- API:
api-alist.pjt.kr - 파일(업로드):
file-alist.pjt.kr - Swagger:
https://api-alist.pjt.kr/swagger-ui/index.html
Docker
- 레지스트리:
registry.pjt.kr - 이미지:
registry.pjt.kr/alist/api - 컨테이너명:
alist-api - 포트:
127.0.0.1:8106->8106/tcp
서버 디렉토리 (/srv/project/alist/)
/srv/project/alist/
├── compose/ # docker-compose 파일
├── data/ # 데이터
├── env/ # 환경변수 파일
├── logs/ # 로그
├── scripts/ # 배포/운영 스크립트
└── uploads/ # 업로드 파일 (file-alist.pjt.kr 루트)
Nginx
file-alist.pjt.kr→/srv/project/alist/uploads(정적 파일 서빙)- HTTP(80) → HTTPS(301) 리다이렉트
- SSL: Let's Encrypt
- 직접 접근 차단 (
allow 127.0.0.1; deny all;)
파일 업로드
- 업로드 저장 경로:
/srv/project/alist/uploads/ - 업로드 파일 접근 URL:
https://file-alist.pjt.kr/{파일경로}
TUS 업로드 운영 메모 (alist)
tusd는 API 내 라이브러리가 아니라 별도 실행형 업로드 서버(Go 바이너리)로 운영- 내부 바인딩:
127.0.0.1:8110 - base path:
/tus/files/ - 임시 업로드 경로:
/srv/project/alist/uploads/tmp - 실행 파일 경로:
/srv/project/alist/tusd/tusd
Nginx 라우팅
https://file-alist.pjt.kr/tus/files/->http://127.0.0.1:8110/tus/files/프록시location /tus/files/는location /보다 구체적이므로 우선 매칭됨location /가 차단(deny all)이어도/tus/files/는 별도 허용 가능
systemd
- 서비스 파일:
/etc/systemd/system/tusd-alist.service User/Group은 실제 서버 계정으로 맞춰야 함 (예:bigfuntnp)- 계정 불일치 시
status=217/USER,Failed to determine user credentials발생
자주 쓰는 점검
sudo ss -ltnp | grep 8110
curl --http1.1 -i -X OPTIONS http://127.0.0.1:8110/tus/files/
curl --http1.1 -i -X OPTIONS https://file-alist.pjt.kr/tus/files/
운영 메모
-max-size는 청크 크기가 아니라 최종 업로드 파일 전체 크기 제한bind: address already in use발생 시 포트 점유 프로세스 확인 후 정리- 인증/권한은 API(
init/complete)에서 관리하고, 실제 업로드 전송은 TUS 경로로 처리