# 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명 - 동일 학생의 학점 한도 경쟁 - 동일 학생의 시간표 충돌 경쟁 - 동일 학생의 같은 강의 중복 경쟁