147 lines
3.6 KiB
Markdown
147 lines
3.6 KiB
Markdown
# course-registration
|
|
|
|
Spring Boot 4.1.1 / Java 21 기반 수강신청 API 예제입니다. 핵심은 CRUD 개수보다 **수강신청 거부 규칙(R1~R8)** 과 **동시 신청 시 정원·학점·시간표 정확성**을 지키는 것입니다.
|
|
|
|
## Scope
|
|
|
|
- 수강신청(Create)
|
|
- 내 수강신청 목록 / 강의 목록·상세(Read)
|
|
- 수강취소(Delete, soft cancel)
|
|
- 신청 수정(Update) API 없음 — 취소 후 재신청
|
|
- 마스터 데이터 CRUD 없음 — Seeder 사용
|
|
- 인증/JWT 없음
|
|
- k6 부하 테스트는 후속 범위
|
|
|
|
상세 규칙은 [`docs/Requirements.md`](docs/Requirements.md)를 기준으로 합니다.
|
|
|
|
## Run local
|
|
|
|
```bash
|
|
./gradlew bootRun
|
|
```
|
|
|
|
기본 profile은 `local`이며 H2 + Seeder가 자동 활성화됩니다.
|
|
|
|
- API: `http://127.0.0.1:8080/api/v1`
|
|
- Swagger UI: `http://127.0.0.1:8080/swagger-ui.html`
|
|
- OpenAPI JSON: `http://127.0.0.1:8080/v3/api-docs`
|
|
- Health: `http://127.0.0.1:8080/actuator/health`
|
|
- H2 console: `http://127.0.0.1:8080/h2-console`
|
|
|
|
## Run dev with PostgreSQL
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# 필요한 값 수정
|
|
docker compose up --build
|
|
```
|
|
|
|
Compose는 host에 `127.0.0.1`로만 노출합니다.
|
|
|
|
```bash
|
|
docker compose down
|
|
# DB volume까지 초기화하려면
|
|
docker compose down -v
|
|
```
|
|
|
|
## Profiles
|
|
|
|
| profile | DB | ddl-auto | Seeder | Swagger |
|
|
|---|---|---|---|---|
|
|
| local | H2 | create-drop | ON | ON |
|
|
| dev | PostgreSQL | update | `APP_SEED_ENABLED` | ON |
|
|
| prod | PostgreSQL | validate | OFF | `SWAGGER_ENABLED` 기본 false |
|
|
|
|
운영 profile의 DB 접속 정보는 반드시 환경변수로 주입합니다.
|
|
|
|
## API
|
|
|
|
```text
|
|
POST /api/v1/users/{userId}/registrations
|
|
GET /api/v1/users/{userId}/registrations?semesterId={semesterId}
|
|
DELETE /api/v1/users/{userId}/registrations/{registrationId}
|
|
GET /api/v1/lessons?semesterId={id}&subjectId={id}&page=0&size=20
|
|
GET /api/v1/lessons/{lessonId}
|
|
```
|
|
|
|
### Concurrency invariant
|
|
|
|
모든 registration mutation은 아래 순서로 row lock을 획득합니다.
|
|
|
|
```text
|
|
User FOR UPDATE
|
|
-> Lesson FOR UPDATE
|
|
-> R4~R8 검증
|
|
-> INSERT / cancel
|
|
```
|
|
|
|
User lock은 동일 학생의 학점·동일과목·시간표 경쟁을 직렬화하고, Lesson lock은 정원 경쟁을 직렬화합니다. 락 순서는 항상 `User -> Lesson`으로 고정합니다.
|
|
|
|
## Local seed IDs
|
|
|
|
Postman과 동일한 고정 ID를 사용합니다.
|
|
|
|
```text
|
|
Semester
|
|
00000000-0000-0000-0000-000000000001
|
|
|
|
1학년 학생
|
|
30000000-0000-0000-0000-000000000001
|
|
|
|
2학년 학생
|
|
30000000-0000-0000-0000-000000000002
|
|
|
|
대학원생
|
|
30000000-0000-0000-0000-000000000003
|
|
|
|
자료구조 01분반
|
|
40000000-0000-0000-0000-000000000001
|
|
|
|
자료구조 02분반 (동일 Subject)
|
|
40000000-0000-0000-0000-000000000002
|
|
|
|
운영체제 (자료구조 01과 월요일 시간 충돌)
|
|
40000000-0000-0000-0000-000000000003
|
|
|
|
정원 1명 강의
|
|
40000000-0000-0000-0000-000000000004
|
|
|
|
최소 3학년 강의
|
|
40000000-0000-0000-0000-000000000005
|
|
|
|
대학원생 전용 강의
|
|
40000000-0000-0000-0000-000000000006
|
|
|
|
월요일 11:00~13:00 경계 테스트 강의
|
|
40000000-0000-0000-0000-000000000007
|
|
```
|
|
|
|
## Postman
|
|
|
|
```text
|
|
postman/
|
|
course-registration.postman_collection.json
|
|
local.postman_environment.json
|
|
dev.postman_environment.json
|
|
```
|
|
|
|
`Register lesson` 요청은 성공 시 응답의 `registrationId`를 environment에 자동 저장합니다.
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
./gradlew test
|
|
./gradlew build
|
|
```
|
|
|
|
테스트에는 다음이 포함됩니다.
|
|
|
|
- R1~R8 규칙 및 경계값
|
|
- 신청/조회/취소/재신청
|
|
- 취소 이력 유지
|
|
- 정원 1명에 동시 10명
|
|
- 정원 30명에 동시 50명
|
|
- 동일 학생의 학점 한도 경쟁
|
|
- 동일 학생의 시간표 충돌 경쟁
|
|
- 동일 학생의 같은 강의 중복 경쟁
|