Skip to content

Latest commit

ย 

History

History
310 lines (253 loc) ยท 8.32 KB

File metadata and controls

310 lines (253 loc) ยท 8.32 KB

๐ŸŒพ Agriculture Insurance Backend API

๋†์—…๋ณดํ—˜ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์˜ Spring Boot ๊ธฐ๋ฐ˜ ๋ฐฑ์—”๋“œ API ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ๋†์—…๋ณดํ—˜ ๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ, ๋‚ ์”จ ์ •๋ณด ์ œ๊ณต, AI ์ฑ„ํŒ… ์ƒ๋‹ด, OAuth2 ์†Œ์…œ ๋กœ๊ทธ์ธ ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ

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

๋†์—…์ธ๊ณผ ๋†์—…๋ณดํ—˜ ์ œ๊ณต์ž๋ฅผ ์œ„ํ•œ ์ข…ํ•ฉ ๋†์—…๋ณดํ—˜ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ

  • ๋†์—…๋ณดํ—˜ ๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ: 67๊ฐ€์ง€ ์ž‘๋ฌผ์— ๋Œ€ํ•œ 4๊ฐ€์ง€ ๋ณด์žฅ ์œ ํ˜•๋ณ„ ๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ
  • ์‹ค์‹œ๊ฐ„ ๋‚ ์”จ ์ •๋ณด: OpenWeatherMap API๋ฅผ ํ†ตํ•œ ๋‚ ์”จ ์˜ˆ๋ณด ์ œ๊ณต
  • AI ์ƒ๋‹ด ์„œ๋น„์Šค: RAG ๊ธฐ๋ฐ˜ ๋†์—…๋ณดํ—˜ ๊ด€๋ จ ์งˆ์˜์‘๋‹ต
  • ๋ณดํ—˜์ƒํ’ˆ ๊ด€๋ฆฌ: ์ž‘๋ฌผ๋ณ„ ๋ณดํ—˜์ƒํ’ˆ ์ •๋ณด ๋ฐ PDF ๋ฌธ์„œ ๊ด€๋ฆฌ
  • ์‚ฌ์šฉ์ž ์ธ์ฆ: OAuth2 ๊ธฐ๋ฐ˜ ์†Œ์…œ ๋กœ๊ทธ์ธ

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

๐Ÿงฎ ๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ ์‹œ์Šคํ…œ

์ง€์› ๋ณด์žฅ ์œ ํ˜•:
โ€ข ์ˆ˜ํ™•๊ฐ์†Œ๋ณด์žฅ (HARVEST_REDUCTION)
โ€ข ์ƒ์‚ฐ๋น„๋ณด์žฅ (PRODUCTION_COST)
โ€ข ์›์˜ˆ์‹œ์„ค ์ƒ์‚ฐ๋น„๋ณด์žฅ (FACILITY_PRODUCTION_COST)
โ€ข ์†ํ•ด๋ณด์žฅ (LOSS)

์ง€์› ์ž‘๋ฌผ๊ตฐ:
โ€ข ๋ฐญ์ž‘๋ฌผ (FIELD_CROPS)
โ€ข ๊ณผ์ˆ˜์ž‘๋ฌผ (FRUIT_CROPS)
โ€ข ์›์˜ˆ์‹œ์„ค (HORTICULTURAL_FACILITY)
โ€ข ๋ฒผ๋งฅ๋ฅ˜ (PADDY_CEREALS)
โ€ข ๋ฒ„์„ฏ๋ฅ˜ (MUSHROOMS)

๐Ÿ” ์ธ์ฆ ์‹œ์Šคํ…œ

  • OAuth2 ์†Œ์…œ ๋กœ๊ทธ์ธ (Google, Kakao, Naver ๋“ฑ)
  • JWT ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ
  • Spring Security ์ ์šฉ

๐Ÿ’ฌ AI ์ฑ„ํŒ… ์‹œ์Šคํ…œ

  • WebSocket ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…
  • ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ (์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ ๋ฐฉ์‹)
  • ๋น„๋™๊ธฐ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ๋กœ ์ˆœ์„œ ๋ณด์žฅ
  • ๋Œ€ํ™” ์š”์•ฝ ๋ฐ ์บ์‹ฑ

๐ŸŒค๏ธ ๋‚ ์”จ ์ •๋ณด

  • OpenWeatherMap API ์—ฐ๋™
  • ์„œ์šธ ์ง€์—ญ ์‹ค์‹œ๊ฐ„ ๋‚ ์”จ
  • ์˜ค๋Š˜/๋‚ด์ผ ์˜ˆ๋ณด ์ •๋ณด

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

Backend

  • Framework: Spring Boot 3.5.0
  • Language: Java 17
  • Database: MySQL (Production), H2 (Test)
  • Security: Spring Security + OAuth2 + JWT
  • Build Tool: Gradle

Dependencies

  • Web: Spring Web, Spring WebFlux
  • Data: Spring Data JPA
  • Security: Spring Security, OAuth2 Client, JWT
  • Validation: Spring Validation
  • Utils: Lombok
  • Test: JUnit 5, Spring Boot Test

Infrastructure

  • Containerization: Docker
  • Reverse Proxy: Nginx
  • External APIs: OpenWeatherMap, FastAPI (AI Chat)

๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

src/main/java/com/aivle/agriculture/
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ auth/           # ์‚ฌ์šฉ์ž ์ธ์ฆ (OAuth2, JWT)
โ”‚   โ”œโ”€โ”€ calculate/      # ๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ ๋กœ์ง
โ”‚   โ”œโ”€โ”€ chat/          # AI ์ฑ„ํŒ… ์‹œ์Šคํ…œ
โ”‚   โ”œโ”€โ”€ detail/        # ๋ณดํ—˜์ƒํ’ˆ ์„ธ๋ถ€์ •๋ณด
โ”‚   โ”œโ”€โ”€ mainpage/      # ๋ฉ”์ธํŽ˜์ด์ง€ (๋‚ ์”จ, ๋ณดํ—˜์ •๋ณด)
โ”‚   โ””โ”€โ”€ test/          # ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ
โ”œโ”€โ”€ global/
โ”‚   โ”œโ”€โ”€ base/          # ๊ธฐ๋ณธ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค
โ”‚   โ”œโ”€โ”€ config/        # ์„ค์ • ํด๋ž˜์Šค๋“ค
โ”‚   โ”œโ”€โ”€ exception/     # ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
โ”‚   โ”œโ”€โ”€ response/      # API ์‘๋‹ต ํ‘œ์ค€ํ™”
โ”‚   โ””โ”€โ”€ security/      # ๋ณด์•ˆ ์„ค์ • (JWT, OAuth2)
โ””โ”€โ”€ AgricultureApplication.java

๋„๋ฉ”์ธ๋ณ„ ์•„ํ‚คํ…์ฒ˜

๊ฐ ๋„๋ฉ”์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค:

controller/    # REST API ์—”๋“œํฌ์ธํŠธ
service/       # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
repository/    # ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต
entity/        # JPA ์—”ํ‹ฐํ‹ฐ
dto/           # ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด

๐Ÿ“š API ๋ฌธ์„œ

์ธ์ฆ API (/api/auth)

GET /api/auth/login/{provider}  # OAuth2 ๋กœ๊ทธ์ธ ์‹œ์ž‘
GET /api/auth/success          # ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฝœ๋ฐฑ
GET /api/auth/failure          # ๋กœ๊ทธ์ธ ์‹คํŒจ ํŽ˜์ด์ง€

๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ API (/api/calc)

POST /api/calc
Content-Type: application/json

{
  "coverageType": "HARVEST_REDUCTION",
  "cropType": "SWEET_POTATO",
  "insuredAmount": 1000000,
  "damageRate": 30.0,
  "selfBurdenRate": 20.0,
  "area": 1000
}

์ฑ„ํŒ… API (/api/chat)

POST /api/chat
Content-Type: application/json

{
  "conversationId": "uuid-string",
  "question": "๋ฒผ ๋†์—…๋ณดํ—˜์— ๋Œ€ํ•ด ์•Œ๋ ค์ฃผ์„ธ์š”"
}

WebSocket ์ฑ„ํŒ…

// ์—ฐ๊ฒฐ
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);

// ๋ฉ”์‹œ์ง€ ์ „์†ก
stompClient.send('/app/chat.send', {}, JSON.stringify(message));

// ์‘๋‹ต ๊ตฌ๋…
stompClient.subscribe('/queue/response', callback);

๋ณดํ—˜์ƒํ’ˆ ์ •๋ณด API (/api/insurance)

GET /api/insurance/{cropType}   # ์ž‘๋ฌผ๋ณ„ ๋ณดํ—˜์ƒํ’ˆ ์ •๋ณด

๋ฉ”์ธํŽ˜์ด์ง€ API (/api/main)

GET /api/main                   # ๋‚ ์”จ ์ •๋ณด + ๋ณดํ—˜ ์ •๋ณด

๐Ÿš€ ์„ค์น˜ ๋ฐ ์‹คํ–‰

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

  • Java 17+
  • MySQL 8.0+
  • Gradle 7.0+

๋กœ์ปฌ ์‹คํ–‰

# ์ €์žฅ์†Œ ํด๋ก 
git clone <repository-url>
cd agriculture-backend

# ์˜์กด์„ฑ ์„ค์น˜ ๋ฐ ๋นŒ๋“œ
./gradlew build

# ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
./gradlew bootRun

Docker ์‹คํ–‰

# Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ
docker build -t agriculture-backend .

# ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
docker run -p 8080:8080 agriculture-backend

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

ํ•„์ˆ˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ •
SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/agriculture
SPRING_DATASOURCE_USERNAME=username
SPRING_DATASOURCE_PASSWORD=password

# OAuth2 ์„ค์ •
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_ID=your-google-client-id
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_SECRET=your-google-client-secret

# JWT ์„ค์ •
JWT_SECRET_KEY=your-jwt-secret-key
JWT_EXPIRATION_TIME=86400000

# ์™ธ๋ถ€ API ์„ค์ •
OPENWEATHER_API_KEY=your-openweather-api-key
FASTAPI_BASE_URL=http://your-fastapi-server

# CORS ์„ค์ •
URL_FRONTEND=http://localhost:3000
URL_TEMP=http://localhost:3001
URL_TEMP2=http://localhost:3002
URL_TEMP3=http://localhost:3003

๋ณด์•ˆ ์„ค์ •

  • CORS: ํ”„๋ก ํŠธ์—”๋“œ URL์— ๋Œ€ํ•œ CORS ํ—ˆ์šฉ
  • Rate Limiting: Nginx๋ฅผ ํ†ตํ•œ ์š”์ฒญ ์†๋„ ์ œํ•œ (IP๋‹น ์ดˆ๋‹น 10๊ฑด)
  • Connection Limiting: ๋™์‹œ ์—ฐ๊ฒฐ ์ œํ•œ (IP๋‹น 10๊ฐœ)

๐Ÿณ ๋ฐฐํฌ

Docker Compose (๊ถŒ์žฅ)

version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    depends_on:
      - mysql

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: agriculture
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx:/etc/nginx/conf.d
    depends_on:
      - app

ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ํ™•์ธ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
  • SSL ์ธ์ฆ์„œ ์„ค์ •
  • ๋กœ๊ทธ ์ˆ˜์ง‘ ์„ค์ •
  • ๋ชจ๋‹ˆํ„ฐ๋ง ์„ค์ •
  • ๋ฐฑ์—… ์ „๋žต ์ˆ˜๋ฆฝ

๐Ÿ‘จโ€๐Ÿ’ป ๊ฐœ๋ฐœ ๊ฐ€์ด๋“œ

์ฝ”๋”ฉ ์ปจ๋ฒค์…˜

  • ํŒจํ‚ค์ง€ ๊ตฌ์กฐ: ๋„๋ฉ”์ธ ์ค‘์‹ฌ ์„ค๊ณ„ (Domain-Driven Design)
  • ๋„ค์ด๋ฐ: ํ•œ๊ธ€ ์ฃผ์„๊ณผ ์˜๋ฌธ ๋ณ€์ˆ˜๋ช… ๋ณ‘ํ–‰
  • API Response: ResponseFactory๋ฅผ ํ†ตํ•œ ํ‘œ์ค€ํ™”๋œ ์‘๋‹ต ํ˜•์‹
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ: ์ „์—ญ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ ์ ์šฉ

์ƒˆ๋กœ์šด ๋„๋ฉ”์ธ ์ถ”๊ฐ€ ์‹œ

  1. domain/{domain-name} ํŒจํ‚ค์ง€ ์ƒ์„ฑ
  2. Controller, Service, Repository, Entity, DTO ํด๋ž˜์Šค ์ƒ์„ฑ
  3. ํ•„์š”์‹œ Config ํด๋ž˜์Šค์— ์„ค์ • ์ถ”๊ฐ€
  4. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

๋ณดํ—˜๋ฃŒ ๊ณ„์‚ฐ๊ธฐ ์ถ”๊ฐ€ ์‹œ

  1. calculator ํŒจํ‚ค์ง€์— ์ƒˆ ๊ณ„์‚ฐ๊ธฐ ํด๋ž˜์Šค ์ƒ์„ฑ
  2. Calculator ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„
  3. CalculateService์— ๊ณ„์‚ฐ๊ธฐ ๋“ฑ๋ก
  4. ํ•ด๋‹น ๋ณด์žฅ ์œ ํ˜•์„ CoverageType enum์— ์ถ”๊ฐ€

์ฑ„ํŒ… ๊ธฐ๋Šฅ ํ™•์žฅ ์‹œ

  • ConversationContextManager: ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ ๋กœ์ง
  • ChatWebSocketHandler: WebSocket ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ
  • ์ฃผ์˜์‚ฌํ•ญ: ๋ฉ”์‹œ์ง€ ์ˆœ์„œ ๋ณด์žฅ์„ ์œ„ํ•ด CompletableFuture ์ฒด์ด๋‹ ์‚ฌ์šฉ

๐Ÿ“Š ์„ฑ๋Šฅ ์ตœ์ ํ™”

์บ์‹ฑ ์ „๋žต

  • ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ: Spring Cache๋ฅผ ํ†ตํ•œ conversation ์บ์‹ฑ
  • ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ: ์ตœ๊ทผ 10๊ฐœ ๋ฉ”์‹œ์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€
  • ์š”์•ฝ ์‹œ์Šคํ…œ: 20๊ฐœ ์ด์ƒ ๋ฉ”์‹œ์ง€ ์‹œ ์ด์ „ ๋Œ€ํ™” ์š”์•ฝ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ตœ์ ํ™”

  • ์ธ๋ฑ์‹ฑ: conversationId์— ๋Œ€ํ•œ ์ธ๋ฑ์Šค ์„ค์ •
  • ํŽ˜์ด์ง•: ๋Œ€ํ™” ์ด๋ ฅ ์กฐํšŒ ์‹œ PageRequest ์‚ฌ์šฉ
  • ์ง€์—ฐ ๋กœ๋”ธ: @ManyToOne(fetch = FetchType.LAZY) ์ ์šฉ