Skip to content

๐Ÿง‘๐Ÿปโ€๐Ÿ’ป๊ฐ•์˜์‹ค ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

Notifications You must be signed in to change notification settings

ClassRoomManager-Woowa-Tech-Course/back

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

85 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๊ฐ•์˜์‹ค ๊ด€๋ฆฌ ์‹œ์Šคํ…œ - Backend

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค - ์˜คํ”ˆ๊ณผ์ œ ๋ฐฑ์—”๋“œ API ์„œ๋ฒ„

๊ฐ•์˜์‹ค ์˜ˆ์•ฝ ๋ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ RESTful API ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ

๐ŸŽฏ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

Spring Boot ๊ธฐ๋ฐ˜์˜ ๊ฐ•์˜์‹ค ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ๋ฐฑ์—”๋“œ API ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ํ•™์ƒ๊ณผ ๊ต์ง์›์˜ ๊ฐ•์˜์‹ค ์˜ˆ์•ฝ, ๊ด€๋ฆฌ์ž์˜ ๊ฐ€์ด๋“œ๋ผ์ธ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ ๊ณ ์žฅ ์‹ ๊ณ ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

โœจ ์ฃผ์š” ๊ธฐ๋Šฅ

1. ์˜ˆ์•ฝ ๊ด€๋ฆฌ

  • ๊ฐ•์˜์‹ค ์˜ˆ์•ฝ ๋“ฑ๋ก
  • ์˜ˆ์•ฝ ์กฐํšŒ (๋ชฉ๋ก/์ƒ์„ธ)
  • ์˜ˆ์•ฝ ์ˆ˜์ • ๋ฐ ์ทจ์†Œ
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜ ์˜ˆ์•ฝ ๋ณดํ˜ธ

2. ๊ฐ€์ด๋“œ๋ผ์ธ ๊ด€๋ฆฌ

  • ๊ฐ•์˜์‹ค๋ณ„ ์‚ฌ์šฉ ๊ฐ€์ด๋“œ๋ผ์ธ ๋“ฑ๋ก
  • ๊ฐ€์ด๋“œ๋ผ์ธ ์กฐํšŒ
  • ํŒŒ์ผ ์ฒจ๋ถ€ (AWS S3 ์—ฐ๋™)

3. ๊ฐ•์˜์‹ค ๊ด€๋ฆฌ

  • ๊ฐ•์˜์‹ค ๋ชฉ๋ก ์กฐํšŒ
  • ์ดˆ๊ธฐ ๊ฐ•์˜์‹ค ๋ฐ์ดํ„ฐ ์ž๋™ ์„ค์ •

4. ์ธ์ฆ/์ธ๊ฐ€

  • JWT ๊ธฐ๋ฐ˜ ๊ด€๋ฆฌ์ž ์ธ์ฆ
  • ์ดˆ๊ธฐ ๊ด€๋ฆฌ์ž ๊ณ„์ • ์ž๋™ ์ƒ์„ฑ

5. ๊ณ ์žฅ ์‹ ๊ณ 

  • ๊ฐ•์˜์‹ค ๊ณ ์žฅ ์‹ ๊ณ 
  • ๊ฐ•์˜์‹ค ๊ณ ์žฅ ์‹ ๊ณ  ๋ชฉ๋ก ์กฐํšŒ
  • ๊ณ ์žฅ ์ˆ˜๋ฆฌ ์™„๋ฃŒ ์ฒ˜๋ฆฌ

๐Ÿ›  ๊ธฐ์ˆ  ์Šคํƒ

Backend Framework

  • Spring Boot 3.x - ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ
  • Spring Data JPA - ORM
  • Spring Security - ์ธ์ฆ/์ธ๊ฐ€
  • Spring Web - RESTful API

Database

  • MySQL 8.0 - ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
  • Docker Compose - ์ปจํ…Œ์ด๋„ˆ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜

Cloud & Storage

  • AWS S3 - ํŒŒ์ผ ์Šคํ† ๋ฆฌ์ง€ (์ด๋ฏธ์ง€/๋ฌธ์„œ)
  • Spring Cloud AWS - AWS SDK ํ†ตํ•ฉ

Security

  • JWT (JSON Web Token) - ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ
  • BCrypt - ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”

Build Tool

  • Gradle (์ถ”์ •)

๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ

ํ•„์ˆ˜ ์š”๊ตฌ์‚ฌํ•ญ

  • Java 17+
  • Docker & Docker Compose
  • AWS ๊ณ„์ • (S3 ์‚ฌ์šฉ)

1. ์ €์žฅ์†Œ ํด๋ก 

git clone [repository-url]
cd classroom-manager-backend

2. Docker๋กœ MySQL ์‹คํ–‰

docker-compose up -d

3. ๋กœ์ปฌ ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ

src/main/resources/application-local.yml ํŒŒ์ผ ์ƒ์„ฑ:

# AWS S3 ์„ค์ •
spring:
  cloud:
    aws:
      s3:
        bucket: {bucket ์ด๋ฆ„}
      credentials:
        access-key: {access key}
        secret-key: {secret-key}

# ๊ด€๋ฆฌ์ž ๊ณ„์ •
admin:
  super:
    id: super_admin
    password: super_admin

# JWT
jwt:
  secret-key: {secret key}

# Frontend URL
front:
  url: http://localhost:5173

โš ๏ธ ๋ณด์•ˆ ์ฃผ์˜์‚ฌํ•ญ:

  • application-local.yml ํŒŒ์ผ์€ ์ ˆ๋Œ€ Git์— ์ปค๋ฐ‹ํ•˜์ง€ ๋งˆ์„ธ์š”
  • .gitignore์— ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”
  • ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋˜๋Š” AWS Secrets Manager ์‚ฌ์šฉ ๊ถŒ์žฅ

4. .gitignore ํ™•์ธ

# ๋ฏผ๊ฐํ•œ ์„ค์ • ํŒŒ์ผ (๋ฐ˜๋“œ์‹œ ํฌํ•จ!)
application-local.yml
application-dev.yml
application-prod.yml

# ๊ธฐํƒ€
.env
*.log
target/
build/

5. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

# Gradle ์‚ฌ์šฉ ์‹œ
./gradlew bootRun --args='--spring.profiles.active=local'

# Maven ์‚ฌ์šฉ ์‹œ
./mvnw spring-boot:run -Dspring-boot.run.profiles=local

IntelliJ IDEA์—์„œ ์‹คํ–‰:

  1. Run โ†’ Edit Configurations
  2. Active profiles์— local ์ž…๋ ฅ
  3. Apply โ†’ OK
  4. ์‹คํ–‰ ๋ฒ„ํŠผ ํด๋ฆญ

์„œ๋ฒ„๊ฐ€ http://localhost:8080์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

โš™๏ธ ํ™˜๊ฒฝ ์„ค์ •

ํ”„๋กœํŒŒ์ผ ๊ตฌ์กฐ

src/main/resources/
โ”œโ”€โ”€ application.yml              # ๊ณตํ†ต ์„ค์ • (Git์— ์ปค๋ฐ‹)
โ”œโ”€โ”€ application-local.yml        # ๋กœ์ปฌ ๊ฐœ๋ฐœ (Git ์ œ์™ธ)
โ”œโ”€โ”€ application-dev.yml          # ๊ฐœ๋ฐœ ์„œ๋ฒ„ (Git ์ œ์™ธ)
โ””โ”€โ”€ application-prod.yml         # ์šด์˜ ์„œ๋ฒ„ (Git ์ œ์™ธ)

application.yml (๊ณตํ†ต ์„ค์ •)

spring:
  application:
    name: manager
  datasource:
    url: jdbc:mysql://localhost:3306/classroom_db?useSSL=false&allowPublicKeyRetrieval=true
    username: classroom_user
    password: classroom_user
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    open-in-view: false
    hibernate:
      ddl-auto: create  # ์šด์˜: validate
    properties:
      hibernate:
        format_sql: true
    show-sql: true
  cloud:
    aws:
      s3:
        bucket: ${AWS_S3_BUCKET:default-bucket}
      region:
        static: "ap-northeast-2"
      credentials:
        access-key: ${AWS_ACCESS_KEY}
        secret-key: ${AWS_SECRET_KEY}

admin:
  super:
    id: ${ADMIN_ID:super_admin}
    password: ${ADMIN_PASSWORD:super_admin}
    name: "์ „์ฒด ๊ด€๋ฆฌ์ž"
    contact: "010-0000-0000"

class:
  code:
    - "5413"
    - "5414"
    - "5527"
    - "5507"
    - "5508"
    - "627-A"
    - "627-B"

jwt:
  access-token-expiration-day: 10
  secret-key: ${JWT_SECRET_KEY}

front:
  url: ${FRONT_URL:http://localhost:5173}

ํ”„๋กœํŒŒ์ผ๋ณ„ ์‹คํ–‰

# ๋กœ์ปฌ ๊ฐœ๋ฐœ
./gradlew bootRun --args='--spring.profiles.active=local'

# ๊ฐœ๋ฐœ ์„œ๋ฒ„
./gradlew bootRun --args='--spring.profiles.active=dev'

# ์šด์˜ ์„œ๋ฒ„
java -jar build/libs/app.jar --spring.profiles.active=prod

5. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

# Gradle ์‚ฌ์šฉ ์‹œ
./gradlew bootRun

# ๋˜๋Š” IDE์—์„œ ์ง์ ‘ ์‹คํ–‰

์„œ๋ฒ„๊ฐ€ http://localhost:8080์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ก API ๋ฌธ์„œ

Base URL

http://localhost:8080/api

์ฃผ์š” ์—”๋“œํฌ์ธํŠธ

์˜ˆ์•ฝ ๊ด€๋ จ API

# ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ
GET /api/reservations/{roomCode}?yearMonth={yearMonth}

# ์˜ˆ์•ฝ ์ƒ์„ธ ์กฐํšŒ
GET /api/reservations/detail/{reservationId}

# ์˜ˆ์•ฝ ๋“ฑ๋ก
POST /api/reservations
Content-Type: application/json

{
  "memberId": "2021001",
  "contact": "010-1234-5678",
  "role": "STUDENT",
  "roomCode": "5413",
  "title": "์Šคํ„ฐ๋””",
  "purpose": "์•Œ๊ณ ๋ฆฌ์ฆ˜ ์Šคํ„ฐ๋””",
  "startDate": "2024-01-15T09:00",
  "endDate": "2024-01-15T11:00",
  "password": "1234"
}

# ์˜ˆ์•ฝ ์ˆ˜์ •
PUT /api/reservations/{reservationId}
Content-Type: application/json

{
  "memberId": "2021001",
  "contact": "010-1234-5678",
  "role": "STUDENT",
  "roomCode": "5413",
  "title": "์Šคํ„ฐ๋””",
  "purpose": "์•Œ๊ณ ๋ฆฌ์ฆ˜ ์Šคํ„ฐ๋””",
  "startDate": "2024-01-15T09:00",
  "endDate": "2024-01-15T11:00",
  "password": "1234"
}

# ์˜ˆ์•ฝ ์ทจ์†Œ
DELETE /api/reservations/{reservationId}
Content-Type: application/json

{
    "password":"1234"
}

๊ฐ€์ด๋“œ๋ผ์ธ ๊ด€๋ จ API

# ๊ฐ€์ด๋“œ๋ผ์ธ ๋ชฉ๋ก ์กฐํšŒ
GET /api/guidelines

# ๊ฐ€์ด๋“œ๋ผ์ธ ์ƒ์„ธ ์กฐํšŒ
GET /api/guidelines/{guideLineId}

# ๊ฐ€์ด๋“œ๋ผ์ธ ๋“ฑ๋ก (๊ด€๋ฆฌ์ž)
POST /api/guidelines
Authorization: Bearer {jwt-token}
Content-Type: multipart/form-data

{
  "guideLine": {
    "roomCode": "5413",
    "content": "๊ฐ•์˜์‹ค ์‚ฌ์šฉ ๊ฐ€์ด๋“œ๋ผ์ธ"
  },
  "files": [ํŒŒ์ผ1, ํŒŒ์ผ2, ...]
}

๊ฐ•์˜์‹ค ๊ด€๋ จ API

# ๊ฐ•์˜์‹ค ๋ชฉ๋ก ์กฐํšŒ
GET /api/classrooms

์ธ์ฆ ๊ด€๋ จ API

# ๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ
POST /api/admins/login
Content-Type: application/json

{
  "adminId": "super_admin",
  "password": "super_admin"
}

# ์‘๋‹ต
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
}

โš™๏ธ ํ™˜๊ฒฝ ์„ค์ •

Docker Compose ์„ค์ •

docker-compose.yml:

version: '3.8'

services:
  mysql-db:
    image: mysql:8.0
    container_name: classroom-manager-db-container
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: admin
      MYSQL_DATABASE: "classroom_db"
      MYSQL_USER: "classroom_user"
      MYSQL_PASSWORD: "classroom_user"
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-time-zone=Asia/Seoul

volumes:
  mysql-data:

MySQL ์ ‘์† ์ •๋ณด

Host: localhost
Port: 3306
Database: classroom_db
Username: classroom_user
Password: classroom_user

์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๋ฐ์ดํ„ฐ:

1. ๊ด€๋ฆฌ์ž ๊ณ„์ •

ID: super_admin
Password: super_admin
Role: SUPER_ADMIN

2. ๊ฐ•์˜์‹ค ๋ชฉ๋ก

- 5413
- 5414
- 5527
- 5507
- 5508
- 627-A
- 627-B

๐Ÿ—„๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ

๊ฐœ๋…์  ๋ชจ๋ธ๋ง

erDiagram
    MEMBER {
        string member_id PK
        string contact
        string role
        string name
    }

    ADMIN {
        string admin_id PK
        string name
        string contact
        string role
        string authorization
        string active
        string password
    }

    CLASSROOM {
        bigint room_id PK
        string roomNumber UK
    }

    REPORT {
        bigint report_id PK
        string member_id FK
        bigint room_id FK
        datetime date
        string item
        string contact
        string content
        string status
    }
    
    RESERVATION {
        bigint reservation_id PK
        string member_id FK
        bigint room_id FK
        string purpose
        datetime start_time
        datetime end_time
    }
    
    GUIDELINE {
        bigint guideline_id PK
        bigint room_id FK
        string content
    }
    
    FILE {
        bigint file_id PK
        string file_type
        string file_url
        string original_filename
        bigint related_id
        string related_type "REPORT, GUIDELINE, RESERVATION"
    }
    
    MEMBER ||--o{ REPORT : "report"
    MEMBER ||--o{ RESERVATION : "reserve"
    CLASSROOM ||--o{ RESERVATION : "has"
    CLASSROOM ||--o{ REPORT : "is_related_to"
    ADMIN ||--o{ GUIDELINE :"creates"
    CLASSROOM ||--o{ GUIDELINE : "is_related_to"
    
    REPORT ||..o{ FILE : "has"
    RESERVATION ||..o{ FILE : "has"
    GUIDELINE ||..o{ FILE : "has"
Loading

๋…ผ๋ฆฌ์  ๋ชจ๋ธ๋ง

erDiagram
    MEMBER {
        string member_id PK
        string contact
        Role role "STUDENT, STAFF"
        string name
    }

    ADMIN {
        string admin_id PK
        string name
        string contact
        string password
        Role role "STUDENT, STAFF"
        Authorization authorization "SUPER_ADMIN, ADMIN, EDITOR, VIEWER"
        Active active "ACTIVE, INACTIVE"
    }

    CLASSROOM {
        bigint room_id PK
        string room_code UK
    }

    REPORT {
        bigint report_id PK
        string member_id FK
        bigint room_id FK
        datetime date
        Item item "PROJECTOR, PC, SPEAKER, MICROPHONE"
        string contact
        string content
        Status status "PENDING, COMPLETED"
    }
    
    RESERVATION {
        bigint reservation_id PK
        string member_id FK
        bigint room_id FK
        string purpose
        datetime start_time
        datetime end_time
    }
    
    GUIDELINE {
        bigint guideline_id PK
        bigint room_id FK
        string admin_id FK
        string content
    }
    
    FILE {
        bigint file_id PK
        string file_url
        string file_type
        string original_filename
        bigint related_id
        string related_type "REPORT, GUIDELINE, RESERVATION"
    }
    
    MEMBER ||--o{ REPORT : "report"
    MEMBER ||--o{ RESERVATION : "reserve"
    CLASSROOM ||--o{ RESERVATION : "has"
    CLASSROOM ||--o{ REPORT : "is_related_to"
    ADMIN ||--o{ GUIDELINE :"creates"
    CLASSROOM ||--o{ GUIDELINE : "is_related_to"
Loading

๐Ÿ“ฆ ์ฃผ์š” ์˜์กด์„ฑ

dependencies {
    // Spring Boot
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    
    // Database
    runtimeOnly 'com.mysql:mysql-connector-j'
    
    // AWS
    implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
    
    // JWT
    implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
    
    // Test
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

๐Ÿ”ง ๊ฐœ๋ฐœ ํŒ

MySQL ์ปจํ…Œ์ด๋„ˆ ๊ด€๋ฆฌ

# ์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘
docker-compose up -d

# ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€
docker-compose down

# ๋กœ๊ทธ ํ™•์ธ
docker-compose logs -f mysql-db

# MySQL ์ ‘์†
docker exec -it classroom-manager-db-container mysql -u classroom_user -p

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”

# ์ปจํ…Œ์ด๋„ˆ ๋ฐ ๋ณผ๋ฅจ ์‚ญ์ œ (๋ฐ์ดํ„ฐ ์™„์ „ ์‚ญ์ œ)
docker-compose down -v

# ์žฌ์‹œ์ž‘
docker-compose up -d

JWT ํ† ํฐ ํ…Œ์ŠคํŠธ

# ๋กœ๊ทธ์ธ
curl -X POST http://localhost:8080/api/admins/login \
  -H "Content-Type: application/json" \
  -d '{"memberId":"super_admin","password":"super_admin"}'

# ์‘๋‹ต์—์„œ ํ† ํฐ ๋ณต์‚ฌ ํ›„ ์‚ฌ์šฉ
curl -X GET http://localhost:8080/api/admins/something \
  -H "Authorization: Bearer {your-token}"

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ

๋ณด์•ˆ

  • โš ๏ธ application.yml์— ์žˆ๋Š” AWS ํ‚ค์™€ JWT secret์€ ์ ˆ๋Œ€ Git์— ์ปค๋ฐ‹ํ•˜์ง€ ๋งˆ์„ธ์š”
  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋˜๋Š” .env ํŒŒ์ผ ์‚ฌ์šฉ ๊ถŒ์žฅ
  • .gitignore์— ๋‹ค์Œ ์ถ”๊ฐ€:
    .env
    application-local.yml
    application-prod.yml
    

DDL ์„ค์ •

  • ๊ฐœ๋ฐœ: spring.jpa.hibernate.ddl-auto: create
  • ์šด์˜: spring.jpa.hibernate.ddl-auto: validate ๋˜๋Š” none

CORS ์„ค์ •

  • ํ”„๋ก ํŠธ์—”๋“œ URL์„ front.url์— ์ •ํ™•ํžˆ ์„ค์ •
  • ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋„๋ฉ”์ธ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ

Woowa-Tech-Course - ์˜คํ”ˆ๊ณผ์ œ

About

๐Ÿง‘๐Ÿปโ€๐Ÿ’ป๊ฐ•์˜์‹ค ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages