|
| 1 | +# Schedule Reservation System API |
| 2 | +고객과 어드민이 각각의 필요에 맞게 시험 일정 예약을 처리할 수 있는 ‘**일정 예약 시스템 API**’입니다. |
| 3 | + |
| 4 | +<br/> |
| 5 | + |
| 6 | +## Tech Stack |
| 7 | +- Language : Ruby 3.2.2 |
| 8 | +- Framework : Rails 8.0.1 |
| 9 | +- Database : PostgreSQL |
| 10 | +- Documentation : Swagger (`rswag 2.16.0`) |
| 11 | + |
| 12 | +<br/> |
| 13 | + |
| 14 | +## Feature |
| 15 | +본 어플리케이션에서 API를 통해 제공하는 기능들입니다. |
| 16 | + |
| 17 | +### 예약 조회 |
| 18 | +- **User** |
| 19 | + - “예약 신청 가능 시간 & 인원” 조회 |
| 20 | + - “본인 등록 예약”만 조회 |
| 21 | +- **Admin** |
| 22 | + - 고객이 등록한 모든 예약 조회 |
| 23 | + |
| 24 | +### 예약 신청 |
| 25 | +- 시험 시작 3일 전까지 신청 가능 |
| 26 | +- 동 시간대 최대 50,000명까지만 예약 가능 |
| 27 | + - 확정되지 않은 예약은 50,000명 제한에 포함되지 않음 |
| 28 | + → 즉, 실제로는 특정 시간대에 50,000명이 넘는 예약 인원이 존재할 수 있음 (확정 처리 안된 예약들) |
| 29 | + - ex. 04/15 14:00 ~ 16:00 - 30,000명 예약 확정 → 20,000명 이하인 추가 예약 신청 가능 |
| 30 | + |
| 31 | +### 예약 확정 |
| 32 | +> **흐름** : 예약 신청(`User`) → 확인 확정(`Admin`) → 시험 운영 일정 반영 |
| 33 | +
|
| 34 | +- 확정되지 않은 예약 → 최대 인원 수 계산 포함 X |
| 35 | +- **Admin** : 모든 고객 예약 확정 가능 |
| 36 | + |
| 37 | +### 예약 수정 |
| 38 | +- **User** : “예약 확정 전” → 본인 예약 수정 가능 |
| 39 | +- **Admin** : 모든 고객 예약 수정 가능 |
| 40 | + |
| 41 | +### 예약 삭제 |
| 42 | +- **User** : 확정 전에 본인 예약 삭제 가능 |
| 43 | +- **Admin** : 모든 고객 예약 삭제 가능 |
| 44 | + |
| 45 | +<br/> |
| 46 | + |
| 47 | +## Exception |
| 48 | +- **예약 신청** |
| 49 | + - User : 50,000명 초과된 시간대 신청한 경우 |
| 50 | + - User : 현재 신청 날짜가 시험 시작일 기준 3일 이내일 경우 |
| 51 | +- **예약 확정** |
| 52 | + - Admin : 확정하고자 하는 시험의 인원 수와 이미 확정된 시간대의 인원 수의 합이 50,000명을 초과할 경우 |
| 53 | +- **예약 수정** |
| 54 | + - User : 확정된 예약에 대해 수정을 시도한 경우 |
| 55 | + - User : 본인이 예약하지 않은 일정에 대해 수정을 시도한 경우 |
| 56 | +- **예약 삭제** |
| 57 | + - User : 확정된 예약에 대해 삭제를 시도한 경우 |
| 58 | + - User : 본인이 예약하지 않은 일정에 대해 수정을 시도한 경우 |
| 59 | + |
| 60 | +<br/> |
| 61 | + |
| 62 | +## Domain |
| 63 | +### Users (`users`) |
| 64 | +| Column | Type | Description | |
| 65 | +|:-------|:---------|:-------------------| |
| 66 | +| `id` | `number` | **Required**. (PK) | |
| 67 | +| `role` | `string` | **Required**. 권한 | |
| 68 | + |
| 69 | +<br/> |
| 70 | + |
| 71 | +### Schedules (`schedules`) |
| 72 | +| Column | Type | Description | |
| 73 | +|:-----------------|:------------|:--------------------| |
| 74 | +| `id` | `number` | **Required**. (PK) | |
| 75 | +| `user_id` | `number` | **Required**. (FK) | |
| 76 | +| `name` | `number` | **Required**. 예약명 | |
| 77 | +| `personnel` | `number` | **Required**. 인원 수 | |
| 78 | +| `start_datetime` | `timestamp` | **Required**. 시작 일시 | |
| 79 | +| `end_datetime` | `timestamp` | **Required**. 종료 일시 | |
| 80 | +| `is_confirm` | `boolean` | **Required**. 확정 여부 | |
| 81 | + |
| 82 | + |
| 83 | +<br/> |
| 84 | + |
| 85 | +## Run Locally |
| 86 | +본 프로젝트를 로컬 환경에서 실행하기 위한 환경 설정 및 실행 방법입니다. |
| 87 | + |
| 88 | +### Before Run |
| 89 | +- **Local** |
| 90 | + - Ruby 3.2.2 설치 필요 |
| 91 | + - Bundler 설치 필요 |
| 92 | + - Rails 8.0.1 설치 필요 |
| 93 | + - Node.js & Yarn 설치 필요 |
| 94 | + - PostgreSQL 설치 필요 |
| 95 | +- **Docker** |
| 96 | + - **Docker** 설치 필요 |
| 97 | + - (Optional) **Compose** 사용 희망 시, 추가 설치 필요 |
| 98 | + |
| 99 | +<br/> |
| 100 | + |
| 101 | +### Run |
| 102 | +> 1. 실행을 위해 필요한 환경변수(`.env`)는 별도 공유가 필요합니다. |
| 103 | +> 2. 요청 시, 주어진 JWT를 사용해야 합니다. |
| 104 | +> 3. Docker로 실행할 경우, Container 로그를 통해 JWT를 확인해야 합니다. |
| 105 | +- **Docker 미사용** 시 |
| 106 | + - 기본적으로 Local 환경에 PostgreSQL이 실행 중이어야 합니다. |
| 107 | + ```shell |
| 108 | + bundle install |
| 109 | + |
| 110 | + dotenv rails s -p 8080 |
| 111 | + ``` |
| 112 | +<br/> |
| 113 | + |
| 114 | +- **Docker 사용** 시 (Docker Compose ❌) |
| 115 | + - 기존 Local에 동일한 이름의 컨테이너가 있는지 확인이 필요합니다. |
| 116 | + - `.env` 파일을 최대한 프로젝트 root에 위치시켜주세요. |
| 117 | + - 만약 `.env` 파일 path는 해당 파일을 다운로드 받은 경로를 입력해야 합니다. |
| 118 | + - 단일 어플리케이션을 위한 단일 데이터베이스 컨테이너이기 때문에 `--link`를 사용합니다. |
| 119 | + ```shell |
| 120 | + docker volume create postgres_data |
| 121 | + docker network create app_network |
| 122 | + # 변수 내부 내용은 직접 입력해주세요. |
| 123 | + # DB Container |
| 124 | + docker run -d --name app_db --network app_network \ |
| 125 | + -e POSTGRES_USER=${DB_USERNAME} \ |
| 126 | + -e POSTGRES_PASSWORD=${DB_PASSWORD} \ |
| 127 | + -e POSTGRES_DB=schedule_reservation_system \ |
| 128 | + -p 5432:5432 \ |
| 129 | + -v postgres_data:/var/lib/postgresql/data \ |
| 130 | + postgres |
| 131 | + |
| 132 | + # Ruby API Application Container |
| 133 | + # 프로젝트 root 위치에 .env 파일이 있다면 해당 파라미터는 생략해도 괜찮습니다. |
| 134 | + docker build --build-args ENV_FILE_PATH=${ENV_FILE_PATH} -t app . |
| 135 | + docker run -d --name app --network app_network \ |
| 136 | + -e DB_NAME=schedule_reservation_system \ |
| 137 | + -e DB_USERNAME=${DB_USERNAME} \ |
| 138 | + -e DB_PASSWORD=${DB_PASSWORD} \ |
| 139 | + -e DB_HOST=app_db \ |
| 140 | + -p 8080:8080 \ |
| 141 | + -w /app \ |
| 142 | + app |
| 143 | + ``` |
| 144 | +- **Docker 사용** 시 (Docker Compose ✅) |
| 145 | + ```shell |
| 146 | + # 프로젝트 root 위치에 .env 파일이 있다면 ENV_FILE_PATH 파라미터는 생략해도 괜찮습니다. |
| 147 | + DB_USERNAME=${DB_USERNAME} DB_PASSWORD=${DB_PASSWORD} ENV_FILE_PATH={ENV_FILE_PATH} docker compose up -d --build |
| 148 | + ``` |
| 149 | + |
| 150 | +<br/> |
| 151 | + |
| 152 | +## API Documentation |
| 153 | +Swagger를 통해 API 문서를 제공합니다. |
| 154 | +위 [Run Locally](#run-locally)를 참고하여 로컬 환경에서 []()에 접속하면 확인할 수 있습니다. |
| 155 | + |
| 156 | +<br/> |
| 157 | + |
| 158 | +## Additional |
| 159 | +> 요청자 식별을 위한 JWT 이용 방식 |
| 160 | +
|
| 161 | +rails 어플리케이션 시 실행되는 콘솔 로그를 확인해주세요. |
| 162 | +```test |
| 163 | +dotenv rails s -p 8080 |
| 164 | +
|
| 165 | +=> Booting Puma |
| 166 | +=> Rails 8.0.1 application starting in development |
| 167 | +=> Run `bin/rails server --help` for more startup options |
| 168 | +
|
| 169 | +... |
| 170 | +> Schedule dummy data insert succeeded |
| 171 | +
|
| 172 | +> User (user_id 1) JWT : eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwicm9sZSI6InVzZXIiLCJpYXQiOjE3Mzg2NjQxNDgsImV4cCI6MTczODc1MDU0OH0.0yzi1eRngKOSf8JbeWzo8csSk3vsaCF8kIefspiQ4zE |
| 173 | +> Admin (user_id 2) JWT : eyJhbGciOiJIUzI1NiJ9.eyJpZCI6Miwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzM4NjY0MTQ4LCJleHAiOjE3Mzg3NTA1NDh9.SBmuNttSs-YGJOc5TZnipmz-cJctwaryXnxVKJ-KSz4 |
| 174 | +Puma starting in single mode... |
| 175 | +* Puma version: 6.6.0 ("Return to Forever") |
| 176 | +... |
| 177 | +``` |
| 178 | + |
| 179 | +<br/> |
| 180 | + |
| 181 | +> API 문서를 Swagger로 채택한 이유 + `rswag` 라이브러리를 채택한 이유 |
| 182 | +
|
| 183 | +어플리케이션 구현 내용에 따라 자동 반영되어 정보 정확성과 편의성 측면에서 이점이 있으며 endpoint를 통한 쉬운 접근성을 근거로 채택했습니다. |
| 184 | + |
| 185 | +라이브러리의 경우, `Rswag` 와 `Grape-Swagger-Rails` 중 `Rswag` 을 채택했습니다. |
| 186 | + |
| 187 | +- Grape를 Rails 환경에서 통합하여 사용할 계획이라면 `grape-swagger-rails`가 적합함. |
| 188 | +- Rails routes와 통합되므로 문서화가 용이함. |
| 189 | +- Rails 컨트롤러를 사용하여 API |
| 190 | +- 자동으로 Swagger 문서를 생성하고, RSpec 기반 테스트와 연동할 수 있어서 유지보수가 편리함. |
| 191 | + |
| 192 | +<br/> |
| 193 | + |
| 194 | +> 에약 시간대 정책 |
| 195 | +
|
| 196 | +요구사항 명세서 내 예시를 참고하여 "시 단위"(Hour)와 "분 단위"(Minute) 중 "**시 단위**"(Hour)를 채택했습니다.<br/> |
| 197 | + |
| 198 | +<br/> |
| 199 | + |
| 200 | +> 예약 가능 일정 조회 기준 설정 |
| 201 | +
|
| 202 | +요청 파라미터를 통해 "월(Month)"을 기준으로 "해당 월에 가능한 일정"을 조회할 수 있도록 했습니다.<br/> |
| 203 | +(요청 파라미터가 존재하지 않을 경우, 조회 시점을 기준으로 월 데이터가 적용됩니다.) |
| 204 | + |
| 205 | +<br/> |
| 206 | + |
| 207 | +> `.gitignore` |
| 208 | +
|
| 209 | +[gitignore.io](https://www.toptal.com/developers/gitignore) - "Ruby", "Rails", "RubyMine" 항목을 적용하여 생성했습니다. |
0 commit comments