@@ -125,44 +125,42 @@ private async Task ProcessChatRequestInternalAsync(ChatProcessContext context)
125125}
126126```
127127
128- ### WebSocket 세션 관리: 실시간 결과 전송
128+ ### 페이지네이션: 대화 기록 조회
129129
130- ** 설명** : WebSocket을 통한 실시간 채팅 결과 전송 시스템. 클라이언트가 ` /ws ` 엔드포인트로 연결하면 채팅 처리 완료 시 결과를 자동으로 수신합니다 .
130+ ** 설명** : 효율적인 대화 기록 조회를 위한 페이지네이션 시스템. 대용량 대화 기록을 페이지 단위로 나누어 조회하고 클라이언트에서 점진적으로 로드할 수 있습니다 .
131131
132132** 구현 위치** :
133- - ** WebSocket 미들웨어 ** : [ ` ProjectVG.Api/Middleware/WebSocketMiddleware .cs ` ] ( ../../ProjectVG.Api/Middleware/WebSocketMiddleware .cs )
134- - ** WebSocket 매니저 ** : [ ` ProjectVG.Application/Services/WebSocket/WebSocketManager .cs ` ] ( ../../ProjectVG.Application/Services/WebSocket/WebSocketManager .cs )
135- - ** 연결 관리 ** : [ ` ProjectVG.Infrastructure/Realtime/WebSocketConnection/WebSocketClientConnection .cs ` ] ( ../../ProjectVG.Infrastructure/Realtime/WebSocketConnection/WebSocketClientConnection .cs )
133+ - ** 대화 컨트롤러 ** : [ ` ProjectVG.Api/Controllers/ConversationController .cs ` ] ( ../../ProjectVG.Api/Controllers/ConversationController .cs )
134+ - ** 대화 서비스 ** : [ ` ProjectVG.Application/Services/Conversation/ConversationService .cs ` ] ( ../../ProjectVG.Application/Services/Conversation/ConversationService .cs )
135+ - ** 대화 리포지토리 ** : [ ` ProjectVG.Infrastructure/Persistence/Repositories/Conversation/SqlServerConversationRepository .cs ` ] ( ../../ProjectVG.Infrastructure/Persistence/Repositories/Conversation/SqlServerConversationRepository .cs )
136136
137137** 핵심 코드** :
138138``` csharp
139- // WebSocket 연결 처리 (미들웨어)
140- if (context .Request .Path == " /ws" && context .WebSockets .IsWebSocketRequest )
139+ // 페이지네이션 조회 (컨트롤러)
140+ [HttpGet (" {characterId}" )]
141+ [JwtAuthentication ]
142+ public async Task < ActionResult < ConversationHistoryResponse >> GetConversationHistory (
143+ Guid characterId ,
144+ [FromQuery ] int page = 1 ,
145+ [FromQuery ] int pageSize = 10 )
141146{
142- var webSocket = await context .WebSockets .AcceptWebSocketAsync ();
143- var userId = await AuthenticateWebSocketAsync (context );
147+ var userId = GetCurrentUserId ();
148+ var history = await _conversationService .GetConversationHistoryAsync (
149+ userId .Value , characterId , page , pageSize );
144150
145- if (userId .HasValue )
146- {
147- await _webSocketManager .AddConnectionAsync (userId .Value , webSocket );
148- await HandleWebSocketCommunication (webSocket , userId .Value );
149- }
151+ return Ok (history );
150152}
151153
152- // 채팅 결과 WebSocket으로 전송
153- public async Task SendChatResultAsync (Guid userId , ChatResult result )
154+ // 데이터베이스 페이지네이션 (리포지토리)
155+ public async Task < IEnumerable < ConversationHistory >> GetConversationHistoryAsync (
156+ Guid userId , Guid characterId , int page , int pageSize )
154157{
155- var connection = _connections .GetValueOrDefault (userId );
156- if (connection != null )
157- {
158- var message = JsonSerializer .Serialize (new WebSocketMessage
159- {
160- Type = " chat_result" ,
161- Data = result
162- });
163-
164- await connection .SendAsync (message );
165- }
158+ return await _context .ConversationHistories
159+ .Where (ch => ch .UserId == userId && ch .CharacterId == characterId )
160+ .OrderByDescending (ch => ch .Timestamp )
161+ .Skip ((page - 1 ) * pageSize )
162+ .Take (pageSize )
163+ .ToListAsync ();
166164}
167165```
168166
@@ -292,51 +290,6 @@ private string? ExtractToken(HttpRequest request)
292290
293291## 3. 크레딧 시스템
294292
295- ### 정밀 계산: Decimal(18,2) 잔액 관리
296-
297- ** 설명** : 금융급 정밀도의 Decimal(18,2) 타입을 사용한 크레딧 잔액 관리
298-
299- ** 구현 위치** :
300- - ** 사용자 엔티티** : [ ` ProjectVG.Domain/Entities/User/User.cs ` ] ( ../../ProjectVG.Domain/Entities/User/User.cs )
301- - ** 크레딧 거래 엔티티** : [ ` ProjectVG.Domain/Entities/Credit/CreditTransaction.cs ` ] ( ../../ProjectVG.Domain/Entities/Credit/CreditTransaction.cs )
302- - ** 크레딧 서비스** : [ ` ProjectVG.Application/Services/Credit/CreditService.cs ` ] ( ../../ProjectVG.Application/Services/Credit/CreditService.cs )
303-
304- ** 핵심 코드** :
305- ``` csharp
306- // 사용자 엔티티의 크레딧 필드
307- [Precision (18 , 2 )]
308- public decimal CreditBalance { get ; set ; } = 0 ;
309-
310- [Precision (18 , 2 )]
311- public decimal TotalCreditsEarned { get ; set ; } = 0 ;
312-
313- [Precision (18 , 2 )]
314- public decimal TotalCreditsSpent { get ; set ; } = 0 ;
315-
316- // 크레딧 거래 엔티티
317- public class CreditTransaction : BaseEntity
318- {
319- [Precision (18 , 2 )]
320- public decimal Amount { get ; set ; }
321-
322- [Precision (18 , 2 )]
323- public decimal BalanceAfter { get ; set ; }
324-
325- public CreditTransactionType Type { get ; set ; } // Earn = 1, Spend = 2
326- }
327-
328- // 크레딧 계산 로직
329- public async Task < decimal > AddCreditsAsync (Guid userId , decimal amount , string source , string description )
330- {
331- var user = await _userRepository .GetByIdAsync (userId );
332- var newBalance = user .CreditBalance + amount ;
333-
334- user .CreditBalance = newBalance ;
335- user .TotalCreditsEarned += amount ;
336-
337- return newBalance ;
338- }
339- ```
340293
341294### 거래 기록: 완전한 audit trail
342295
@@ -548,15 +501,6 @@ public bool CanBeViewedBy(Guid? userId)
548501 return userId .HasValue && IsOwnedBy (userId .Value );
549502}
550503
551- // 편집 권한 확인
552- public bool CanBeEditedBy (Guid ? userId )
553- {
554- // 시스템 캐릭터는 편집 불가
555- if (IsSystemCharacter ()) return false ;
556-
557- // 소유자만 편집 가능
558- return userId .HasValue && IsOwnedBy (userId .Value );
559- }
560504```
561505
562506### 프롬프트 생성: 설정 기반 SystemPrompt 구성
@@ -601,11 +545,4 @@ public string BuildSystemPrompt()
601545}
602546```
603547
604- ---
605-
606- ## 📚 추가 리소스
607-
608- - ** API 문서** : [ README.md] ( ../../README.md )
609- - ** 아키텍처 가이드** : [ CLAUDE.md] ( ../../CLAUDE.md )
610- - ** 개발 환경 설정** : [ scripts/] ( ../../scripts/ ) 디렉토리
611- - ** 테스트 가이드** : [ ProjectVG.Tests/] ( ../../ProjectVG.Tests/ ) 디렉토리
548+ <br >
0 commit comments