Skip to content

Commit 249bba9

Browse files
authored
feat(be): AiChat 엔티티 및 ERD 수정 (#1) (#6)
* GitHub Actions AI PR 리뷰 워크플로우 추가 - Grok-4-fast 모델 사용 - 글로벌 익셉션 처리, ApiResponse 사용, Kotlin 최적화, ktlint 규칙 검토 - PR 생성/수정 시 자동 코드 리뷰 실행 * feat(be): AiChatMessage + Session + Enum Class 생성 및 erd 수정 * feat: ai pr리뷰 오류수정 * fix: GitHub Actions HEREDOC 문법 에러 수정 * fix: AI PR 리뷰 워크플로우 완전 수정 * fix: AI PR 리뷰가 우리 글로벌 규칙 체크하도록 수정
1 parent 61f4db6 commit 249bba9

File tree

6 files changed

+147
-7
lines changed

6 files changed

+147
-7
lines changed

.github/workflows/ai-pr-review.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: AI Code Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
7+
jobs:
8+
ai-review:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
pull-requests: write
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
19+
- uses: actions/github-script@v7
20+
env:
21+
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
22+
with:
23+
script: |
24+
const diff = await github.rest.repos.compareCommits({
25+
owner: context.repo.owner,
26+
repo: context.repo.repo,
27+
base: context.payload.pull_request.base.sha,
28+
head: context.payload.pull_request.head.sha
29+
});
30+
31+
const kotlinFiles = diff.data.files.filter(file =>
32+
(file.filename.endsWith('.kt') || file.filename.endsWith('.kts')) && file.patch
33+
);
34+
35+
if (kotlinFiles.length === 0) return;
36+
37+
for (const file of kotlinFiles.slice(0, 3)) {
38+
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
39+
method: 'POST',
40+
headers: {
41+
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
42+
'Content-Type': 'application/json'
43+
},
44+
body: JSON.stringify({
45+
model: 'x-ai/grok-4-fast:free',
46+
messages: [{
47+
role: 'system',
48+
content: `코드 리뷰어입니다. 다음 규칙을 검토하세요:
49+
50+
## 필수 검토 항목
51+
1. **글로벌 익셉션 처리**: @ControllerAdvice 사용, 표준 에러 응답
52+
2. **ApiResponse 사용**: 모든 API는 ApiResponse<T>로 감싸서 응답
53+
3. **Kotlin 최적화**: data class, null safety, when 표현식, 확장함수 등
54+
4. **ktlint 규칙**: 포맷팅, 네이밍 컨벤션
55+
56+
## 응답 형식
57+
🟢 **좋은점**: [규칙을 잘 지킨 부분]
58+
🟡 **개선사항**: [더 좋게 할 수 있는 부분]
59+
🔴 **문제점**: [반드시 수정해야 할 부분]`
60+
}, {
61+
role: 'user',
62+
content: `파일: ${file.filename}\n\n변경사항:\n${file.patch}`
63+
}],
64+
max_tokens: 500,
65+
temperature: 0
66+
})
67+
});
68+
69+
if (response.ok) {
70+
const result = await response.json();
71+
const review = result.choices[0].message.content;
72+
73+
await github.rest.pulls.createReview({
74+
owner: context.repo.owner,
75+
repo: context.repo.repo,
76+
pull_number: context.payload.pull_request.number,
77+
body: `## 🤖 AI 리뷰 - \`${file.filename}\`\n\n${review}`,
78+
event: 'COMMENT'
79+
});
80+
}
81+
}

docs/erd-diagram.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ erDiagram
4747
bigint session_id FK "세션 ID"
4848
text content "메시지 내용"
4949
enum sender_type "USER, AI"
50-
json metadata "AI 도구 사용 정보"
5150
datetime created_at "메시지 전송 시간"
5251
}
5352
@@ -143,7 +142,6 @@ AI 채팅 메시지를 저장하는 테이블입니다.
143142
| session_id | BIGINT | FK, NOT NULL | 세션 ID |
144143
| content | TEXT | NOT NULL | 메시지 내용 |
145144
| sender_type | ENUM | NOT NULL | 발신자 유형 (USER, AI) |
146-
| metadata | JSON | NULL | AI 도구 사용 정보 (WeatherTool, TourTool) |
147145
| created_at | DATETIME | NOT NULL | 메시지 전송 시간 |
148146

149147
**제약조건:**
@@ -243,7 +241,7 @@ Guest가 AI 채팅 세션과 채팅방을 평가하는 테이블입니다.
243241
1. User → AiChatSession 생성
244242
2. User → AiChatMessage 전송
245243
3. Spring AI → WeatherTool/TourTool 호출
246-
4. AI → AiChatMessage(sender_type=AI) 생성 + metadata 저장
244+
4. AI → AiChatMessage(sender_type=AI) 생성
247245
5. SSE로 실시간 응답 전송
248246
```
249247

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.back.koreaTravelGuide.domain.ai.aiChat.entity
2+
3+
import jakarta.persistence.Column
4+
import jakarta.persistence.Entity
5+
import jakarta.persistence.EnumType
6+
import jakarta.persistence.Enumerated
7+
import jakarta.persistence.FetchType
8+
import jakarta.persistence.GeneratedValue
9+
import jakarta.persistence.GenerationType
10+
import jakarta.persistence.Id
11+
import jakarta.persistence.JoinColumn
12+
import jakarta.persistence.ManyToOne
13+
import jakarta.persistence.Table
14+
import java.time.ZoneId
15+
import java.time.ZonedDateTime
16+
17+
@Entity
18+
@Table(name = "ai_chat_messages")
19+
class AiChatMessage(
20+
@Id
21+
@GeneratedValue(strategy = GenerationType.IDENTITY)
22+
@Column(name = "id")
23+
val id: Long? = null,
24+
@ManyToOne(fetch = FetchType.LAZY)
25+
@JoinColumn(name = "session_id", nullable = false)
26+
val aiChatSession: AiChatSession,
27+
@Column(name = "content", columnDefinition = "TEXT", nullable = false)
28+
val content: String,
29+
@Enumerated(EnumType.STRING)
30+
@Column(name = "sender_type", nullable = false)
31+
val senderType: SenderType,
32+
@Column(name = "created_at", nullable = false)
33+
val createdAt: ZonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul")),
34+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.back.koreaTravelGuide.domain.ai.aiChat.entity
2+
3+
import jakarta.persistence.Column
4+
import jakarta.persistence.Entity
5+
import jakarta.persistence.GeneratedValue
6+
import jakarta.persistence.GenerationType
7+
import jakarta.persistence.Id
8+
import jakarta.persistence.Table
9+
import java.time.ZoneId
10+
import java.time.ZonedDateTime
11+
12+
@Entity
13+
@Table(name = "ai_chat_sessions")
14+
class AiChatSession(
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.IDENTITY)
17+
@Column(name = "id")
18+
val id: Long? = null,
19+
@Column(name = "user_id", nullable = false)
20+
val userId: Long,
21+
@Column(name = "session_title", nullable = true, length = 100)
22+
var sessionTitle: String? = null,
23+
@Column(name = "created_at", nullable = false)
24+
val createdAt: ZonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul")),
25+
)

src/main/kotlin/com/back/koreaTravelGuide/domain/ai/aiChat/entity/ChatHistory.kt

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.back.koreaTravelGuide.domain.ai.aiChat.entity
2+
3+
enum class SenderType {
4+
USER,
5+
AI,
6+
}

0 commit comments

Comments
 (0)