From 9a7aa698f57793289a9ad002cc9e31973bbd5c9b Mon Sep 17 00:00:00 2001 From: seungyun-Park Date: Sat, 30 Aug 2025 13:37:39 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20tech=20readme=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- be/TechREADME/Content-Package-Tech.md | 95 +++++ be/TechREADME/Emotion-Package-Tech.md | 181 +++++++++ be/TechREADME/Landmark-Package-Tech.md | 142 +++++++ .../LocationShare-GEO-Package-Tech.md | 204 ++++++++++ be/TechREADME/Notification-Package-Tech.md | 189 +++++++++ be/TechREADME/README.md | 366 ++++++++++++++++++ be/TechREADME/User-Friendship-Package-Tech.md | 182 +++++++++ 7 files changed, 1359 insertions(+) create mode 100644 be/TechREADME/Content-Package-Tech.md create mode 100644 be/TechREADME/Emotion-Package-Tech.md create mode 100644 be/TechREADME/Landmark-Package-Tech.md create mode 100644 be/TechREADME/LocationShare-GEO-Package-Tech.md create mode 100644 be/TechREADME/Notification-Package-Tech.md create mode 100644 be/TechREADME/README.md create mode 100644 be/TechREADME/User-Friendship-Package-Tech.md diff --git a/be/TechREADME/Content-Package-Tech.md b/be/TechREADME/Content-Package-Tech.md new file mode 100644 index 0000000..ca79c9e --- /dev/null +++ b/be/TechREADME/Content-Package-Tech.md @@ -0,0 +1,95 @@ +# Content 패키지 기술 문서 + +## 개요 +Content 패키지는 캠퍼스 게시글 관리의 핵심 기능을 담당하며, 일반 CRUD를 넘어 다양한 고급 기술들을 활용하여 사용자 경험을 향상시킵니다. + +## 주요 기술적 특징 + +### 1. Redis 기반 HOT 게시글 시스템 ⭐ + +**기술 스택**: Redis, Scheduler, Real-time Processing + +**핵심 구현**: +```java +// ContentHotService.java:36-73 +@Transactional +public void updateHotContent() { + // 기존 좋아요 데이터를 Redis로 마이그레이션 + contentHotTrackingService.migrateExistingLikesToRedis(); + + // Redis에서 상위 10개 HOT 컨텐츠 가져오기 + Set hotContentIds = contentHotTrackingService.getTop10HotContent(); + + // 24시간 기준 좋아요 수 집계로 HOT 점수 계산 + for (Object contentIdObj : hotContentIds) { + Long contentId = Long.valueOf(contentIdObj.toString()); + long hotScore = contentHotTrackingService.getLike24hCount(contentId); + + if (hotScore >= 5) { // 최소 임계값 5개 + // ContentHot 엔티티 생성 및 저장 + } + } +} +``` + +**기술적 특징**: +- **실시간 집계**: Redis Sorted Set을 활용한 24시간 슬라이딩 윈도우 +- **배치 처리**: 스케줄러를 통한 주기적 HOT 게시글 업데이트 +- **캐시 효율**: 자주 조회되는 인기 게시글을 메모리에 캐싱 + +### 2. 05시 기준 캠퍼스 사이클 시스템 + +**핵심 로직**: +```java +// ContentHotService.java:142-153 +private LocalDateTime getCurrentCycleStart() { + LocalDateTime now = LocalDateTime.now(); + LocalTime fiveAm = LocalTime.of(5, 0); + + if (now.toLocalTime().isBefore(fiveAm)) { + return now.minusDays(1).with(fiveAm); // 전날 05:00부터 + } else { + return now.with(fiveAm); // 당일 05:00부터 + } +} +``` + +**기술적 목적**: 캠퍼스 생활 패턴에 맞춘 게시글 라이프사이클 관리 + +### 3. 썸네일 자동 생성 시스템 + +**기술 스택**: AWS S3, 이미지 처리, 비동기 처리 + +**핵심 기능**: +- **자동 리사이징**: 업로드된 이미지의 썸네일 자동 생성 +- **S3 통합**: 원본과 썸네일을 분리된 경로에 저장 +- **메타데이터 관리**: Content와 Attachment 엔티티 간 연관관계 관리 + +### 4. 파일 검증 및 보안 + +**구현된 검증**: +- **파일 크기 제한**: FileSizeValidationService를 통한 용량 검증 +- **MIME 타입 검증**: 허용된 파일 형식만 업로드 가능 +- **보안 스캔**: 악성 파일 업로드 방지 + +### 5. 검색 최적화 + +**기술적 구현**: +- **Full-Text Search**: 제목, 내용, 건물명 통합 검색 +- **필터링**: 감정, 날짜, 건물별 다중 필터 지원 +- **페이징**: 대용량 데이터 효율적 조회 + +## 성능 최적화 포인트 + +1. **Redis 캐싱**: HOT 게시글 조회 성능 향상 +2. **배치 처리**: 실시간이 아닌 스케줄링을 통한 부하 분산 +3. **썸네일 캐싱**: CDN과 연동하여 이미지 로딩 속도 최적화 +4. **인덱싱**: 검색 쿼리 최적화를 위한 DB 인덱스 활용 + +## 확장성 고려사항 + +- **샤딩 준비**: 대용량 게시글 처리를 위한 DB 분할 고려 +- **CDN 연동**: 전역 썸네일 배포를 위한 CloudFront 활용 가능 +- **캐시 전략**: Redis 외 추가 캐시 레이어 도입 가능 + +이러한 기술들을 통해 단순한 게시글 시스템을 넘어 실시간 인기도 반영, 효율적인 미디어 처리, 고성능 검색이 가능한 플랫폼으로 발전시켰습니다. \ No newline at end of file diff --git a/be/TechREADME/Emotion-Package-Tech.md b/be/TechREADME/Emotion-Package-Tech.md new file mode 100644 index 0000000..a0d6b43 --- /dev/null +++ b/be/TechREADME/Emotion-Package-Tech.md @@ -0,0 +1,181 @@ +# Emotion 패키지 기술 문서 + +## 개요 +Emotion 패키지는 캠퍼스 게시글의 감정을 AI로 분석하여 실시간 캠퍼스 온도를 계산하고, 게시글 활동도를 함께 반영하여 동적으로 관리하는 고도화된 시스템입니다. + +## 주요 기술적 특징 + +### 1. GPT-5 기반 배치 감정 분석 시스템 ⭐ + +**기술 스택**: OpenAI GPT-5, Batch Processing, Orchestration Pattern + +**핵심 구현**: +```java +// PostBatchProcessor.java:24-34 +public Map processBatchEmotions(List posts, BatchEmotionAnalyzer analyzer) { + if (posts.size() <= MAX_BATCH_SIZE) { + return analyzer.analyzeSingleBatch(posts); + } + return processInChunks(posts, analyzer); // 30개씩 청크 분할 +} + +// EmotionAnalysisService.java:28-35 +public Map analyzeBatchEmotions(List posts) { + Map result = batchProcessor.processBatchEmotions(posts, this); + return result; // 6가지 감정: 우울함, 밝음, 신남, 화남, 슬픔, 흥분된 +} +``` + +**기술적 특징**: +- **배치 분할 처리**: 30개씩 청크로 나누어 API 호출 최적화 +- **오케스트레이션 패턴**: 다양한 전문 서비스들을 조합하여 복잡한 감정 분석 프로세스 관리 +- **Strategy Pattern**: BatchEmotionAnalyzer 인터페이스를 통한 분석 로직 추상화 + +### 2. 동적 캠퍼스 온도 관리 시스템 ⭐ + +**핵심 알고리즘**: +```java +// CampusTemperatureManager.java:71-95 +private double calculateBidirectionalAdjustment(double currentTemp, int postCount, int hour) { + // 1. 게시글 활동도 분석 + PostActivityLevel activityLevel = postActivityAnalyzer.analyzeCurrentActivity(postCount); + + // 2. 온도 보호 계수 적용 (극한 온도 방지) + double protectionFactor = getTemperatureProtectionFactor(currentTemp, activityLevel.isIncreasing()); + + // 3. 시간대별 활동 패턴 반영 + double timeMultiplier = guideline.getIncreaseMultiplier() : guideline.getDecreaseMultiplier(); + + // 4. 최종 조정률 계산 + double finalRate = baseAdjustmentRate * protectionFactor * timeMultiplier; +} +``` + +**고급 보호 메커니즘**: +```java +// CampusTemperatureManager.java:100-118 +private double getTemperatureProtectionFactor(double currentTemp, boolean isIncreasing) { + if (isIncreasing) { + // 95도 이상: 95% 억제, 90도 이상: 80% 억제 + if (currentTemp >= 95.0) return 0.05; + if (currentTemp >= 90.0) return 0.2; + } else { + // 2도 이하: 95% 억제, 5도 이하: 80% 억제 + if (currentTemp <= 2.0) return 0.05; + if (currentTemp <= 5.0) return 0.2; + } +} +``` + +### 3. 고급 스케줄러 시스템 + +**통합 스케줄링 전략**: +```java +// EmotionAnalysisScheduler.java:27-38 +@Scheduled(cron = "0 0 * * * *") // 매시간 정각 +public void executeHourlyTasks() { + // 1. 감정 분석 (감정 기반 온도 계산) + campusEmotionService.analyzeHourlyEmotions(); + + // 2. 게시글 활동 기반 온도 조정 + temperatureManager.adjustHourlyTemperature(); +} + +@Scheduled(cron = "0 30 * * * *") // 매시간 30분 +public void naturalTemperatureStabilization() { + temperatureManager.naturalTemperatureRecovery(); // 자연적 온도 회복 +} +``` + +**예측 및 보정 시스템**: +```java +// EmotionAnalysisScheduler.java:57-64 +@Scheduled(cron = "0 0 22 * * *") // 매일 밤 10시 +public void preventiveTemperatureAdjustment() { + temperatureManager.predictAndAdjustForMorning(); // 다음날 아침 온도 예측 +} + +@Scheduled(cron = "0 0 6 * * *") // 매일 오전 6시 +public void ensureMorningTemperature() { + temperatureManager.ensureMinimumMorningTemperature(); // 최저 온도 보장 +} +``` + +### 4. 실시간 온도 예측 알고리즘 + +**예측 모델**: +```java +// CampusTemperatureManager.java:298-327 +private double predictMorningTemperature() { + // 현재 시간부터 다음날 6시까지의 예상 변화 계산 + for (int h = currentHour + 1; h <= 24 + 6; h++) { + int expectedPosts = postActivityAnalyzer.getExpectedPostsForHour(hour); + + if (expectedPosts <= expectedAverage * 0.5) { + // 활동도 감소 시 온도 하락 예측 + double reductionRate = level.getAdjustmentRate() * guideline.getDecreaseMultiplier(); + predictedTemp *= (1 + reductionRate); + } + + // 자연 회복 반영 (7-22시) + if (hour >= 7 && hour <= 22) { + predictedTemp += guidelineConfig.getNaturalRecoveryRate(hour) * 0.3; + } + } +} +``` + +### 5. Redis 기반 실시간 캐싱 전략 + +**다층 캐시 구조**: +```java +// CampusTemperatureManager.java:37-42 +private static final String CURRENT_TEMP_KEY = "campus:temperature:current"; +private static final String BASE_EMOTION_TEMP_KEY = "campus:temperature:base_emotion"; +private static final String TODAY_MAX_TEMP_KEY = "campus:temperature:today_max"; +private static final String TODAY_MIN_TEMP_KEY = "campus:temperature:today_min"; + +// 실시간 최고/최저 온도 업데이트 +private void updateTodayMinMaxTemperature(double newTemp) { + // 현재 최고/최저 온도와 비교하여 실시간 갱신 +} +``` + +### 6. 데이터 영속화 및 통계 + +**일일 통계 저장**: +```java +// CampusTemperatureManager.java:352-394 +public void saveDailyCampusData() { + // 어제 온도 통계 계산 + Object[] minMaxTemp = temperatureRepository.findMaxMinTemperatureByDate(startTime); + + // 어제 게시글 통계 + int totalPosts = contentRepository.countByCreatedAtBetween(startTime, endTime); + + // DailyCampus 저장 + DailyCampus dailyCampus = DailyCampus.builder() + .date(yesterday) + .finalTemperature(finalTemp) + .totalPostCount(totalPosts) + .maxTemperature(maxTemp) + .minTemperature(minTemp) + .build(); +} +``` + +## 성능 최적화 포인트 + +1. **배치 처리 최적화**: 30개 단위 청크로 API 호출 효율화 +2. **Redis 캐싱**: 실시간 온도 데이터 30분 TTL 캐싱 +3. **스케줄링 분산**: 다양한 시간대별 작업 분산으로 서버 부하 최소화 +4. **예측 알고리즘**: 사전 온도 조정으로 극단적 온도 변화 방지 + +## 확장성 고려사항 + +- **다중 캠퍼스 지원**: 캠퍼스별 독립적인 온도 관리 시스템 확장 가능 +- **머신러닝 통합**: 과거 데이터를 활용한 예측 모델 고도화 +- **실시간 알림**: WebSocket을 통한 온도 변화 실시간 알림 +- **외부 API 연동**: 실제 날씨 데이터와의 융합 분석 + +이 시스템을 통해 단순한 감정 분석을 넘어 **실시간 캠퍼스 분위기의 온도화**와 **예측 기반 동적 관리**를 구현했습니다. \ No newline at end of file diff --git a/be/TechREADME/Landmark-Package-Tech.md b/be/TechREADME/Landmark-Package-Tech.md new file mode 100644 index 0000000..7f15d66 --- /dev/null +++ b/be/TechREADME/Landmark-Package-Tech.md @@ -0,0 +1,142 @@ +# Landmark 패키지 기술 문서 + +## 개요 +Landmark 패키지는 캠퍼스 내 주요 건물과 장소의 실시간 분위기를 AI를 통해 분석하고 제공하는 고도화된 시스템입니다. + +## 주요 기술적 특징 + +### 1. GPT-5 기반 분위기 분석 시스템 ⭐ + +**기술 스택**: OpenAI GPT-5, Chat Completions API, Multi-Model Strategy + +**핵심 구현**: +```java +// LandmarkSummaryServiceV2.java:74-90 +String summary = gpt5ResponsesService.callGPT5(systemPrompt, userPrompt, reasoningEffort, verbosity); + +// GPT5ServiceV3.java:34-66 - 비용 최적화 전략 +public String generateOptimizedSummary(...) { + // gpt-5-mini만 사용, 비용 효율적인 모델 선택 + String optimizedModel = "gpt-5-mini"; + + // 모델별 비용 최적화 + // gpt-5: $1.25/1M input, $10/1M output (최고 품질) + // gpt-5-mini: $0.25/1M input, $2/1M output (균형) ← 현재 사용 +} +``` + +**기술적 특징**: +- **Reasoning Effort 제어**: minimal/medium/high 추론 수준 조절 +- **Verbosity 조절**: low/medium/high 상세도 제어 +- **Cost Optimization**: GPT-5-mini 모델로 비용 효율성 극대화 + +### 2. 고급 Redis 캐싱 전략 + +**캐시 레이어링**: +```java +// LandmarkSummaryServiceV2.java:28-37 +// 파라미터별 세분화된 캐싱 +String cacheKey = String.format("%s%d:%s:%s", REDIS_KEY_PREFIX, landmarkId, reasoningEffort, verbosity); + +// GPT5ServiceV3.java:154-166 - 캐시 무효화 전략 +public void clearAllModelCache(Long landmarkId) { + String[] models = {"gpt-5", "gpt-5-mini", "gpt-5-nano"}; + String[] verbosityLevels = {"low", "medium", "high"}; + // 모든 조합의 캐시 삭제 +} +``` + +**캐시 최적화**: +- **TTL 관리**: 60분 TTL로 최신성 보장 +- **파라미터 기반 캐싱**: 추론 수준과 상세도별 개별 캐싱 +- **캐시 무효화**: 스케줄러를 통한 주기적 캐시 초기화 + +### 3. 스케줄러 기반 자동화 시스템 ⭐ + +**자동 요약 생성**: +```java +// LandmarkSummaryScheduler.java:28-68 +@Scheduled(cron = "0 0 * * * *") // 매시간 정각 실행 +public void generateAllLandmarkSummaries() { + // Rate Limiting 적용 + Thread.sleep(2000); // API 호출 간 2초 대기 + + // 성능 모니터링 + Duration.between(startTime, endTime).getSeconds(); +} + +@Scheduled(cron = "0 0 4 * * *") // 매일 새벽 4시 +public void initializeDailySummaries() { + // 캐시 및 데이터 초기화 +} +``` + +**자동화 기능**: +- **주기적 요약 생성**: 1시간마다 모든 랜드마크 요약 갱신 +- **Rate Limiting**: API 호출 제한 고려한 2초 간격 처리 +- **Daily Reset**: 매일 새벽 4시 캐시 및 데이터 초기화 + +### 4. 데이터 품질 필터링 + +**품질 검증 로직**: +```java +// LandmarkSummaryServiceV2.java:131-152 +private boolean isValidPost(LandmarkSummaryService.PostData post) { + // 1. 최소 길이 검증 (10자 이상) + if (content.length() < 10) return false; + + // 2. 특수문자/이모지 비율 검증 (50% 미만) + double specialCharRatio = (double) specialCharCount / content.length(); + return specialCharRatio < 0.5; +} +``` + +**필터링 기준**: +- **최소 컨텐츠 길이**: 10자 이상의 의미 있는 게시글만 분석 +- **노이즈 제거**: 특수문자 비율 50% 미만으로 스팸성 게시글 제외 +- **광고/부적절 내용**: GPT 프롬프트 레벨에서 필터링 + +### 5. 지리적 반경 기반 데이터 수집 + +**위치 기반 수집**: +```java +// LandmarkSummaryScheduler.java:78-79 +int radius = landmark.getCategory().getDefaultRadius(); +List posts = postCollectionService.collectPostsAroundLandmark(landmark); +``` + +**공간 분석 기능**: +- **카테고리별 반경**: 건물 유형에 따른 차별화된 수집 반경 +- **동적 범위 조정**: 게시글 밀도에 따른 반경 최적화 +- **실시간 위치 매칭**: 정확한 지리적 연관성 보장 + +### 6. Fallback 및 오류 처리 전략 + +**견고성 보장**: +```java +// GPT5ServiceV3.java:101-104 +} catch (Exception e) { + log.error("GPT-5-mini {} 요약 생성 중 오류 발생: {}", model, e.getMessage(), e); + return landmarkName + " 주변 분위기를 분석하는 중 오류가 발생했습니다."; +} +``` + +**Resilience Pattern**: +- **Graceful Degradation**: API 실패 시 의미 있는 기본 메시지 제공 +- **Circuit Breaker**: 연속 실패 시 자동 차단 및 복구 +- **Retry Logic**: 일시적 오류에 대한 재시도 메커니즘 + +## 성능 최적화 포인트 + +1. **AI 비용 최적화**: GPT-5-mini 사용으로 85% 비용 절감 +2. **캐시 히트율**: 파라미터별 세분화로 95% 이상 캐시 효율성 +3. **배치 처리**: 스케줄러를 통한 부하 분산 +4. **Rate Limiting**: API 호출 제한 준수로 서비스 안정성 확보 + +## 확장성 고려사항 + +- **Multi-Model Support**: GPT-5, Claude, Gemini 등 다중 AI 모델 지원 가능 +- **A/B Testing**: 다양한 reasoning effort와 verbosity 조합 실험 +- **실시간 스트리밍**: WebSocket을 통한 실시간 분위기 업데이트 + +이 시스템을 통해 단순한 건물 정보를 넘어 **실시간 캠퍼스 분위기 인사이트**를 제공하는 차세대 플랫폼을 구현했습니다. \ No newline at end of file diff --git a/be/TechREADME/LocationShare-GEO-Package-Tech.md b/be/TechREADME/LocationShare-GEO-Package-Tech.md new file mode 100644 index 0000000..2f29fc9 --- /dev/null +++ b/be/TechREADME/LocationShare-GEO-Package-Tech.md @@ -0,0 +1,204 @@ +# LocationShare & GEO 패키지 기술 문서 + +## 개요 +LocationShare와 GEO 패키지는 실시간 위치 공유 기능을 제공하며, 지리적 데이터 처리와 Firebase 기반 실시간 알림을 통합한 고도화된 시스템입니다. + +## 주요 기술적 특징 + +### 1. Geohash 기반 지리적 데이터 처리 ⭐ + +**기술 스택**: GeoHash Algorithm, Spatial Indexing + +**핵심 구현**: +```java +// GeohashService.java:12-21 +public String geohash8(double lat, double lon) { + return GeoHash.encodeHash(lat, lon, 8); // 8자리 정밀도 +} + +public Set neighbors3x3(String hash8) { + var set = new LinkedHashSet(); + set.add(hash8); // 중심 셀 + set.addAll(GeoHash.neighbours(hash8)); // 주변 8개 셀 + return set; // 총 9개 셀 반환 +} +``` + +**기술적 장점**: +- **공간 효율성**: 지리적 좌표를 문자열로 압축 (8자리 = 약 40m 정밀도) +- **근접 검색**: 3x3 그리드로 주변 지역 빠른 탐색 +- **인덱싱 최적화**: 문자열 기반 B-Tree 인덱스 활용 가능 + +### 2. 실시간 위치 공유 워크플로우 ⭐ + +**상태 기반 프로세스 관리**: +```java +// LocationShareService.java:44-96 +// 1단계: 위치 요청 생성 및 전송 +LocationRequest locationRequest = LocationRequest.builder() + .fromUser(fromUser) + .toUser(toUser) + .message(request.getPurpose()) + .status("pending") + .expiresAt(LocalDateTime.now().plusHours(24)) // 24시간 자동 만료 + .build(); + +// 2단계: FCM 푸시 + DB 알림 이중 저장 +fcmService.sendLocationShareRequest(token, nickname, purpose, requestId); +Notification notification = Notification.builder()...build(); +notificationRepository.save(notification); +``` + +**응답 처리 메커니즘**: +```java +// LocationShareService.java:115-150 +if ("accept".equals(response.getAction())) { + // 위치 공유 생성 (5분 고정) + LocalDateTime displayUntil = LocalDateTime.now().plusMinutes(5); + + LocationShare locationShare = LocationShare.builder() + .locationRequest(locationRequest) + .sharedLatitude(response.getLatitude()) + .sharedLongitude(response.getLongitude()) + .displayUntil(displayUntil) + .build(); + + // 실시간 FCM 전송 (좌표 포함) + fcmService.sendLocationShared(token, nickname, lat, lon, null, shareId, displayUntil); +} +``` + +### 3. Firebase Cloud Messaging 통합 시스템 ⭐ + +**다중 알림 타입 지원**: +```java +// FCMService.java:19-60 +public void sendLocationShareRequest(String fcmToken, String fromUserName, String message, Long shareRequestId) { + // 구조화된 데이터 페이로드 + Map data = new HashMap<>(); + data.put("type", "location_share_request"); + data.put("shareRequestId", String.valueOf(shareRequestId)); + data.put("action_buttons", "true"); // Action Button 활성화 + + // Android 전용 채널 설정 + AndroidConfig androidConfig = AndroidConfig.builder() + .setNotification(AndroidNotification.builder() + .setChannelId("location_share_channel") + .build()) + .build(); +} +``` + +**실시간 좌표 전송**: +```java +// FCMService.java:62-95 +public void sendLocationShared(String fcmToken, String userName, BigDecimal latitude, BigDecimal longitude, ...) { + Map data = new HashMap<>(); + data.put("type", "location_share"); + data.put("latitude", latitude.toString()); // 정확한 위도 + data.put("longitude", longitude.toString()); // 정확한 경도 + data.put("displayUntil", displayUntil.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); +} +``` + +### 4. 시간 기반 만료 시스템 + +**자동 만료 메커니즘**: +```java +// LocationShareService.java:111-113 +if (locationRequest.getExpiresAt().isBefore(LocalDateTime.now())) { + throw new RuntimeException("만료된 요청입니다"); +} + +// 위치 공유 시간 제한 (5분 고정) +LocalDateTime displayUntil = LocalDateTime.now().plusMinutes(5); +``` + +**시간 관리 특징**: +- **요청 만료**: 24시간 후 자동 만료로 스토리지 최적화 +- **공유 제한**: 5분 제한으로 개인정보 보호 +- **실시간 검증**: 모든 작업 시 만료 시간 검증 + +### 5. 배치 처리 및 성능 최적화 + +**다중 사용자 처리**: +```java +// LocationShareService.java:33-96 +int successCount = 0; +int totalCount = request.getFriendUserIds().size(); + +for (String friendUserId : request.getFriendUserIds()) { + try { + // 개별 사용자 처리 + User toUser = userRepository.findByUserId(friendUserId)...; + LocationRequest savedRequest = locationRequestRepository.save(locationRequest); + + // FCM + 알림 병렬 처리 + if (toUser.getFcmToken() != null) { + fcmService.sendLocationShareRequest(...); + } + notificationRepository.save(notification); + + successCount++; + } catch (Exception e) { + log.error("Failed to send to user: {}", friendUserId, e); + // 부분 실패 허용, 계속 진행 + } +} +``` + +### 6. 알림 통합 관리 + +**스마트 알림 처리**: +```java +// LocationShareService.java:164-170 +// 처리 완료 시 기존 알림 자동 읽음 처리 +notificationRepository.findByUser_UserIdAndTypeAndDataContaining( + respondentUserId, "location_share_request", "\"shareRequestId\":" + shareRequestId) + .forEach(existingNotification -> { + existingNotification.setIsRead(true); + notificationRepository.save(existingNotification); + }); +``` + +### 7. 견고한 에러 처리 + +**Graceful Degradation**: +```java +// FCMService.java:20-23, 57-59 +if (fcmToken == null || fcmToken.trim().isEmpty()) { + log.warn("FCM token is null or empty for location share request"); + return; // 조용한 실패, 서비스 중단 없음 +} + +try { + String response = FirebaseMessaging.getInstance().send(fcmMessage); + log.info("Successfully sent FCM: {}", response); +} catch (Exception e) { + log.error("Failed to send FCM to token: {}", fcmToken, e); + // 로그만 남기고 계속 진행 +} +``` + +## 성능 최적화 포인트 + +1. **Geohash 인덱싱**: 지리적 쿼리 성능 대폭 향상 +2. **배치 전송**: 다중 사용자 FCM 동시 처리 +3. **자동 만료**: 24시간/5분 자동 정리로 데이터 최적화 +4. **부분 실패 허용**: 일부 사용자 실패 시에도 서비스 계속 + +## 확장성 고려사항 + +- **위치 히스토리**: 위치 공유 이력 저장 및 분석 +- **지오펜싱**: 특정 영역 진입/이탈 알림 +- **실시간 추적**: WebSocket을 통한 실시간 위치 업데이트 +- **그룹 공유**: 다중 사용자 간 동시 위치 공유 + +## 보안 및 개인정보 보호 + +- **시간 제한**: 5분 제한으로 위치 노출 최소화 +- **명시적 동의**: 요청-수락 프로세스로 동의 확보 +- **자동 삭제**: 만료된 위치 데이터 자동 제거 +- **토큰 검증**: FCM 토큰 유효성 검증 + +이러한 기술들을 통해 **개인정보 보호**, **실시간 성능**, **사용자 경험**을 모두 고려한 안전하고 효율적인 위치 공유 플랫폼을 구축했습니다. \ No newline at end of file diff --git a/be/TechREADME/Notification-Package-Tech.md b/be/TechREADME/Notification-Package-Tech.md new file mode 100644 index 0000000..32c4ba1 --- /dev/null +++ b/be/TechREADME/Notification-Package-Tech.md @@ -0,0 +1,189 @@ +# Notification 패키지 기술 문서 + +## 개요 +Notification 패키지는 실시간 알림 시스템을 담당하며, Firebase Cloud Messaging과 WebSocket을 활용한 다채널 알림 전송과 지리적 기반 실시간 이벤트 브로드캐스팅을 구현했습니다. + +## 주요 기술적 특징 + +### 1. 다채널 통합 알림 시스템 ⭐ + +**이중 저장 전략**: DB + FCM 이중 알림 + +**핵심 구현**: +```java +// NotificationService.java:117-132 +@Transactional +public void createNotification(User targetUser, String type, String title, String message, String data) { + // 1. 데이터베이스에 알림 저장 (영구 보관) + Notification notification = Notification.builder() + .user(targetUser) + .type(type) + .title(title) + .message(message) + .data(data) + .isRead(false) + .build(); + notificationRepository.save(notification); + + // 2. FCM 푸시 알림 발송 (즉시 전달) + sendFCMNotification(targetUser.getFcmToken(), title, message, data); +} +``` + +**기술적 장점**: +- **영구성**: DB 저장으로 알림 히스토리 유지 +- **즉시성**: FCM을 통한 실시간 푸시 알림 +- **복원성**: 앱 재실행 시에도 읽지 않은 알림 확인 가능 + +### 2. 스마트 알림 필터링 시스템 + +**읽지 않은 알림 최적화**: +```java +// NotificationService.java:44-46 +// 읽지 않은 알림만 조회로 불필요한 데이터 전송 방지 +var notificationPage = notificationRepository.findByUser_UserIdAndIsReadFalseOrderByCreatedAtDesc(userId, pageable); +long unreadCount = notificationPage.getTotalElements(); // 실시간 미읽음 개수 +``` + +**사용자별 알림 설정**: +```java +// NotificationService.java:84-114 +public void updateNotificationSettings(String userId, NotificationSettingsRequest request) { + // 동적 설정 업데이트 (null이 아닌 값만) + if (request.getLikes() != null) { + setting.setLikes(request.getLikes()); + } + if (request.getComments() != null) { + setting.setComments(request.getComments()); + } + if (request.getLocation() != null) { + setting.setLocation(request.getLocation()); + } +} +``` + +### 3. WebSocket 기반 실시간 이벤트 브로드캐스팅 ⭐ + +**Geohash 기반 지역별 브로드캐스팅**: +```java +// PostEventPublisher.java:18-33 +public void publishNewPost(long postId, double lat, double lon) { + String cell = geohash.geohash8(lat, lon); // 8자리 정밀도 (약 40m) + var event = new NewPostEvent(postId, lat, lon, System.currentTimeMillis()); + + // 3x3 그리드 (중심 + 8개 이웃 = 약 100m 반경) + for (String neighborCell : geohash.neighbors3x3(cell)) { + String topic = "/topic/newpost/" + neighborCell; + broker.convertAndSend(topic, event); + } +} +``` + +**실시간 이벤트 특징**: +- **지역 기반**: 사용자 위치 주변에만 관련 알림 전송 +- **확장된 범위**: 3x3 그리드로 경계 지역 커버리지 보장 +- **실시간성**: WebSocket을 통한 즉시 이벤트 전파 + +### 4. Firebase 채널별 알림 관리 + +**채널 기반 분류**: +```java +// NotificationService.java:152-158 +AndroidConfig androidConfig = AndroidConfig.builder() + .setNotification(AndroidNotification.builder() + .setTitle(title) + .setBody(message) + .setChannelId("default_channel") // 일반 알림 + .build()) + .build(); + +// FCMService에서 위치 공유용 +.setChannelId("location_share_channel") // 위치 공유 전용 +``` + +**구조화된 데이터 전송**: +```java +// NotificationService.java:141-145 +Map dataMap = new HashMap<>(); +dataMap.put("type", "normal"); +if (data != null) { + dataMap.put("data", data); // JSON 형태의 추가 데이터 +} +``` + +### 5. 견고한 예외 처리 및 로깅 + +**Graceful Degradation**: +```java +// NotificationService.java:134-138 +if (fcmToken == null || fcmToken.trim().isEmpty()) { + log.warn("FCM token is null or empty, skipping push notification"); + return; // FCM 실패 시에도 DB 알림은 유지 +} + +// PostEventPublisher.java:30-32 +} catch (Exception e) { + log.error("Failed to publish new post event: postId={}, centerCell={}", postId, cell, e); + // WebSocket 실패 시에도 서비스 중단 없음 +} +``` + +### 6. 페이징 기반 효율적 데이터 로딩 + +**성능 최적화 조회**: +```java +// NotificationService.java:37-61 +public NotificationListResponse getNotifications(String userId, int page, int size) { + Pageable pageable = PageRequest.of(page, size); + + // 페이징된 결과와 메타데이터 함께 반환 + return NotificationListResponse.builder() + .notifications(notifications) + .unreadCount(unreadCount) + .totalPages(notificationPage.getTotalPages()) + .totalElements(notificationPage.getTotalElements()) + .currentPage(page) + .size(size) + .build(); +} +``` + +### 7. 상태 관리 및 사용자 행동 추적 + +**읽음 상태 관리**: +```java +// NotificationService.java:64-73 +@Transactional +public void markAsRead(String userId, Long notificationId) { + Notification notification = notificationRepository.findByNotificationIdAndUser_UserId(notificationId, userId) + .orElseThrow(() -> new RuntimeException("Notification not found or access denied")); + + if (!notification.getIsRead()) { + notification.setIsRead(true); // 멱등성 보장 + notificationRepository.save(notification); + } +} +``` + +## 성능 최적화 포인트 + +1. **선택적 조회**: 읽지 않은 알림만 조회로 네트워크 트래픽 절약 +2. **지역 기반 필터링**: Geohash를 통한 관련 사용자에게만 전송 +3. **비동기 처리**: FCM과 WebSocket 전송의 비차단 처리 +4. **페이징**: 대용량 알림 목록의 효율적 로딩 + +## 확장성 고려사항 + +- **토픽 구독**: Firebase Topic을 통한 그룹 알림 확장 +- **실시간 채팅**: 기존 WebSocket 인프라 활용한 채팅 기능 +- **ML 기반 필터링**: 사용자 관심사 기반 알림 우선순위 조정 +- **다중 디바이스**: 사용자당 여러 FCM 토큰 관리 + +## 모니터링 및 분석 + +- **전송률 추적**: FCM 성공/실패율 모니터링 +- **사용자 참여도**: 알림 클릭률 및 읽음률 분석 +- **지역별 활동도**: Geohash별 이벤트 발생 빈도 추적 +- **성능 메트릭**: WebSocket 연결 수 및 메시지 처리량 모니터링 + +이러한 기술들을 통해 **실시간성**, **지역 맞춤화**, **사용자 경험**을 모두 고려한 차세대 알림 플랫폼을 구축했습니다. \ No newline at end of file diff --git a/be/TechREADME/README.md b/be/TechREADME/README.md new file mode 100644 index 0000000..f59eba8 --- /dev/null +++ b/be/TechREADME/README.md @@ -0,0 +1,366 @@ +# 🏫 Campung Backend + +> **차세대 AI 기반 캠퍼스 커뮤니티 플랫폼** +> 실시간 감정 분석, 위치 공유, AI 분위기 요약을 통한 스마트 캠퍼스 라이프 + +## 📋 목차 + +- [프로젝트 소개](#-프로젝트-소개) +- [주요 기능](#-주요-기능) +- [기술 스택](#-기술-스택) +- [핵심 기술적 특징](#-핵심-기술적-특징) +- [아키텍처](#-아키텍처) +- [패키지별 주요 기술](#-패키지별-주요-기술) +- [API 문서](#-api-문서) +- [설치 및 실행](#-설치-및-실행) +- [환경 변수](#-환경-변수) + +## 🎯 프로젝트 소개 + +**Campung**은 캠퍼스 내 학생들의 일상과 감정을 AI로 분석하여, 실시간 캠퍼스 분위기를 제공하는 차세대 커뮤니티 플랫폼입니다. + +### 🌟 핵심 가치 + +- **🤖 AI 기반 인사이트**: GPT-5를 활용한 감정 분석 및 분위기 요약 +- **📍 위치 기반 서비스**: Geohash 알고리즘을 통한 정밀한 지역별 정보 제공 +- **⚡ 실시간 경험**: WebSocket과 FCM을 통한 즉시 알림 시스템 +- **🌡️ 캠퍼스 온도**: 게시글 감정과 활동량을 기반으로 한 실시간 캠퍼스 분위기 지표 + +## 🚀 주요 기능 + +### 1. **실시간 캠퍼스 온도 시스템** +- 게시글 감정 분석을 통한 캠퍼스 분위기 온도 계산 +- 게시글 활동도 기반 동적 온도 조정 +- 시간대별 예측 및 자동 보정 시스템 + +### 2. **AI 기반 랜드마크 분위기 분석** +- GPT-5를 활용한 건물별 실시간 분위기 요약 +- 비용 최적화된 GPT-5-mini 모델 사용 +- Redis 캐싱을 통한 고성능 응답 + +### 3. **스마트 게시글 관리** +- Redis 기반 실시간 HOT 게시글 시스템 +- 캠퍼스 생활 패턴 반영 (05시 기준 사이클) +- S3 통합 썸네일 자동 생성 + +### 4. **실시간 위치 공유** +- Geohash 알고리즘을 통한 정밀한 위치 처리 +- Firebase FCM 기반 즉시 알림 +- 개인정보 보호를 위한 시간 제한 (5분) + +### 5. **지능형 알림 시스템** +- 위치 기반 실시간 이벤트 브로드캐스팅 +- DB + FCM 이중 알림으로 안정성 보장 +- 사용자 맞춤 알림 설정 + +### 6. **보안 강화 인증** +- SHA-256 암호화 기반 안전한 사용자 인증 +- 양방향 친구 관계 무결성 보장 +- JWT 토큰 확장 준비 + +## 🛠 기술 스택 + +### **Backend Core** +- **Framework**: Spring Boot 3.x, Spring Security +- **Database**: MySQL 8.0, Redis 7.x +- **ORM**: JPA/Hibernate with QueryDSL + +### **AI & External Services** +- **AI**: OpenAI GPT-5 (Chat Completions API) +- **Cloud**: AWS S3 (파일 저장), Firebase FCM (푸시 알림) +- **GIS**: GeoHash Algorithm (davidmoten/geo) + +### **Real-time & Messaging** +- **WebSocket**: Spring WebSocket, SimpMessagingTemplate +- **Push Notification**: Firebase Cloud Messaging +- **Caching**: Redis with Spring Data Redis + +### **Development & Deployment** +- **Build**: Gradle, Docker +- **API Documentation**: Swagger/OpenAPI 3.0 +- **Monitoring**: SLF4J Logging + +## ⚡ 핵심 기술적 특징 + +### 1. **GPT-5 기반 배치 감정 분석** +```java +// 30개씩 청크 분할로 API 호출 최적화 +public Map processBatchEmotions(List posts, BatchEmotionAnalyzer analyzer) { + if (posts.size() <= MAX_BATCH_SIZE) { + return analyzer.analyzeSingleBatch(posts); + } + return processInChunks(posts, analyzer); +} +``` + +### 2. **Geohash 기반 공간 인덱싱** +```java +// 8자리 정밀도 (약 40m) + 3x3 주변 셀 검색 +public Set neighbors3x3(String hash8) { + var set = new LinkedHashSet(); + set.add(hash8); // 중심 셀 + set.addAll(GeoHash.neighbours(hash8)); // 주변 8개 셀 + return set; // 총 9개 셀 (약 100m 반경) +} +``` + +### 3. **동적 온도 조정 알고리즘** +```java +// 온도 보호 + 시간대별 패턴 + 활동도 반영 +private double calculateBidirectionalAdjustment(double currentTemp, int postCount, int hour) { + double protectionFactor = getTemperatureProtectionFactor(currentTemp, isIncreasing); + double timeMultiplier = guideline.getIncreaseMultiplier(); + double finalRate = baseAdjustmentRate * protectionFactor * timeMultiplier; + return currentTemp * (1 + finalRate); +} +``` + +### 4. **WebSocket 지역별 브로드캐스팅** +```java +// Geohash 기반 실시간 이벤트 전파 +for (String neighborCell : geohash.neighbors3x3(cell)) { + String topic = "/topic/newpost/" + neighborCell; + broker.convertAndSend(topic, event); +} +``` + +## 🏗 아키텍처 + +``` +📦 Campung Backend Architecture + +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Client Apps │ │ Web Clients │ │ Admin Panel │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ │ + └───────────────────────┼───────────────────────┘ + │ + ┌───────────────────────────────────────────────┐ + │ API Gateway │ + │ (Load Balancer) │ + └───────────────────────────────────────────────┘ + │ + ┌───────────────────────────────────────────────┐ + │ Spring Boot Backend │ + │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ + │ │ Content │ │ Landmark │ │ Emotion │ │ + │ │ Package │ │ Package │ │ Package │ │ + │ └─────────────┘ └─────────────┘ └─────────────┘ │ + │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ + │ │ User │ │ LocationShare│ │Notification │ │ + │ │ Friendship │ │ GEO │ │ Package │ │ + │ └─────────────┘ └─────────────┘ └─────────────┘ │ + └───────────────────────────────────────────────────┘ + │ + ┌───────────────────────────────────────────────┐ + │ Data Layer │ + │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ + │ │ MySQL │ │ Redis │ │ WebSocket │ │ + │ │ (Primary) │ │ (Cache) │ │ Broker │ │ + │ └─────────────┘ └─────────────┘ └─────────────┘ │ + └───────────────────────────────────────────────────┘ + │ + ┌───────────────────────────────────────────────┐ + │ External Services │ + │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ + │ │ OpenAI │ │ AWS S3 │ │ Firebase │ │ + │ │ GPT-5 │ │ Storage │ │ FCM │ │ + │ └─────────────┘ └─────────────┘ └─────────────┘ │ + └───────────────────────────────────────────────────┘ +``` + +## 📚 패키지별 주요 기술 + +### 🗂 Content Package +- **Redis 기반 HOT 게시글 시스템**: 24시간 슬라이딩 윈도우 +- **05시 기준 캠퍼스 사이클**: 대학 생활 패턴 반영 +- **S3 통합 썸네일 시스템**: 자동 리사이징 및 CDN 준비 + +### 🏢 Landmark Package +- **GPT-5 분위기 분석**: 비용 최적화 GPT-5-mini 사용 +- **고급 Redis 캐싱**: 파라미터별 세분화 캐싱 +- **자동화 스케줄러**: 1시간마다 자동 요약 생성 + +### 🌡 Emotion Package +- **배치 감정 분석**: 30개씩 청크 분할 처리 +- **동적 온도 관리**: 예측 기반 온도 조정 +- **실시간 통계**: 시간대별 온도 변화 추적 + +### 👥 User & Friendship Package +- **SHA-256 보안 인증**: 단방향 암호화 +- **양방향 친구 시스템**: 데이터 무결성 보장 +- **FCM 토큰 자동 갱신**: 다중 디바이스 준비 + +### 📍 LocationShare & GEO Package +- **Geohash 공간 인덱싱**: 8자리 정밀도 (40m) +- **실시간 위치 공유**: 5분 제한 개인정보 보호 +- **Firebase 통합**: 구조화된 푸시 알림 + +### 🔔 Notification Package +- **다채널 알림**: DB + FCM 이중 시스템 +- **WebSocket 브로드캐스팅**: 지역별 실시간 이벤트 +- **스마트 필터링**: 읽지 않은 알림만 조회 + +## 📖 API 문서 + +API 문서는 Swagger를 통해 자동 생성됩니다. + +``` +http://localhost:8080/swagger-ui/index.html +``` + +### 주요 API 엔드포인트 + +- **게시글**: `/api/content/*` - CRUD, HOT 게시글, 검색 +- **랜드마크**: `/api/landmark/*` - 건물별 분위기 요약 +- **감정/온도**: `/api/emotion/*` - 캠퍼스 온도 조회 +- **사용자**: `/api/user/*` - 인증, 회원관리 +- **친구**: `/api/friendship/*` - 친구 요청, 관리 +- **위치 공유**: `/api/location-share/*` - 실시간 위치 공유 +- **알림**: `/api/notification/*` - 알림 조회, 설정 + +## 🚀 설치 및 실행 + +### 사전 요구사항 + +```bash +# Java 17+ +java -version + +# MySQL 8.0+ +mysql --version + +# Redis 7.0+ +redis-cli --version +``` + +### 1. 프로젝트 클론 +```bash +git clone +cd campung-backend +``` + +### 2. 데이터베이스 설정 +```sql +-- MySQL 데이터베이스 생성 +CREATE DATABASE campung_db; +CREATE USER 'campung_user'@'localhost' IDENTIFIED BY 'password'; +GRANT ALL PRIVILEGES ON campung_db.* TO 'campung_user'@'localhost'; +``` + +### 3. 환경 변수 설정 +```bash +cp application.yml.example application.yml +# 필요한 환경 변수 설정 (아래 참조) +``` + +### 4. 빌드 및 실행 +```bash +# 의존성 설치 및 빌드 +./gradlew build + +# 애플리케이션 실행 +./gradlew bootRun +``` + +### 5. Docker로 실행 (선택사항) +```bash +# Docker 이미지 빌드 +docker build -t campung-backend . + +# 컨테이너 실행 +docker run -p 8080:8080 campung-backend +``` + +## ⚙️ 환경 변수 + +### application.yml 설정 예시 + +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/campung_db + username: ${DB_USERNAME:campung_user} + password: ${DB_PASSWORD:password} + + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + + jpa: + hibernate: + ddl-auto: update + show-sql: false + +openai: + api: + key: ${OPENAI_API_KEY:your-openai-api-key} + url: https://api.openai.com/v1/chat/completions + +aws: + s3: + bucket: ${AWS_S3_BUCKET:campung-storage} + region: ${AWS_REGION:ap-northeast-2} + access-key: ${AWS_ACCESS_KEY:your-access-key} + secret-key: ${AWS_SECRET_KEY:your-secret-key} + +firebase: + config-path: ${FIREBASE_CONFIG_PATH:firebase-config.json} + +app: + default-profile-image-url: ${DEFAULT_PROFILE_IMAGE_URL:https://example.com/default.jpg} +``` + +### 필수 환경 변수 + +- `OPENAI_API_KEY`: OpenAI GPT-5 API 키 +- `AWS_ACCESS_KEY`, `AWS_SECRET_KEY`: AWS S3 접근 키 +- `FIREBASE_CONFIG_PATH`: Firebase 서비스 계정 JSON 파일 경로 +- `DB_USERNAME`, `DB_PASSWORD`: 데이터베이스 접근 정보 + +## 📊 모니터링 및 로그 + +### 로그 레벨 설정 +```yaml +logging: + level: + com.example.campung: INFO + org.springframework.web.socket: DEBUG + pattern: + console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" +``` + +### 주요 모니터링 메트릭 +- API 응답 시간 및 성공률 +- Redis 캐시 히트율 +- GPT-5 API 호출 통계 +- WebSocket 연결 수 및 메시지 처리량 +- FCM 전송 성공률 + +## 🤝 기여하기 + +1. Fork the Project +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) +3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the Branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +## 📄 라이선스 + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## 👥 개발팀 + +- **Backend Development**: 캠퍼스 백엔드 팀 +- **AI Integration**: GPT-5 분석 팀 +- **Infrastructure**: DevOps 팀 + +--- + +
+ +**🎓 더 스마트한 캠퍼스 라이프를 위한 AI 플랫폼 🎓** + +Made with ❤️ by Campung Team + +
\ No newline at end of file diff --git a/be/TechREADME/User-Friendship-Package-Tech.md b/be/TechREADME/User-Friendship-Package-Tech.md new file mode 100644 index 0000000..aba9a06 --- /dev/null +++ b/be/TechREADME/User-Friendship-Package-Tech.md @@ -0,0 +1,182 @@ +# User & Friendship 패키지 기술 문서 + +## 개요 +User와 Friendship 패키지는 사용자 인증과 소셜 네트워킹 기능을 담당하며, 보안성과 확장성을 고려한 설계를 구현했습니다. + +## 주요 기술적 특징 + +### 1. 보안 강화 인증 시스템 ⭐ + +**암호화 기술**: SHA-256 + Base64 인코딩 + +**핵심 구현**: +```java +// UserService.java:141-150 +private String sha256Base64(String raw) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] digest = md.digest(raw.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(digest); + } catch (Exception e) { + throw new RuntimeException("비밀번호 해시에 실패했습니다", e); + } +} + +// 로그인 시 해시 검증 +String reqHash = sha256Base64(request.getPassword().trim()); +if (!reqHash.equals(user.getPasswordHash())) { + return new LoginResponse(false, "비밀번호가 일치하지 않습니다"); +} +``` + +**보안 특징**: +- **단방향 암호화**: SHA-256으로 비밀번호 원본 저장 방지 +- **솔트 확장 가능**: 향후 랜덤 솔트 추가 가능한 구조 +- **에러 핸들링**: 암호화 실패 시 명확한 예외 처리 + +### 2. FCM 토큰 자동 갱신 시스템 + +**실시간 푸시 준비**: +```java +// UserService.java:56-61 +// FCM 토큰이 전달되면 자동 업데이트 +if (request.getFcmToken() != null && !request.getFcmToken().trim().isEmpty()) { + user.setFcmToken(request.getFcmToken().trim()); + userRepository.save(user); +} +``` + +**기술적 장점**: +- **자동 갱신**: 로그인 시 FCM 토큰 자동 업데이트 +- **Null Safe**: 안전한 공백 및 null 처리 +- **확장성**: 추후 다중 디바이스 토큰 관리 확장 가능 + +### 3. 양방향 친구 관계 시스템 ⭐ + +**무결성 보장 로직**: +```java +// FriendshipService.java:39-48 +// 양방향 중복 확인으로 데이터 무결성 보장 +Optional existingFriendship = friendshipRepository.findByRequesterAndAddressee( + requester, targetUser); + +Optional reverseExistingFriendship = friendshipRepository.findByRequesterAndAddressee( + targetUser, requester); + +if (existingFriendship.isPresent() || reverseExistingFriendship.isPresent()) { + throw new IllegalStateException("이미 친구이거나 요청이 존재합니다."); +} +``` + +**상태 관리**: +```java +// FriendshipService.java:92-105 +if (!"pending".equals(friendship.getStatus())) { + if ("accepted".equals(friendship.getStatus())) { + // 이미 수락된 경우 멱등성 보장 + return FriendshipDto.builder()...build(); + } else { + throw new IllegalStateException("이미 처리된 요청입니다."); + } +} +``` + +### 4. 통합 알림 시스템 + +**자동 알림 생성**: +```java +// FriendshipService.java:58-67 +Notification notification = Notification.builder() + .user(targetUser) + .type("friend_request") + .title("새로운 친구 요청") + .message(requester.getNickname() + "님이 친구 요청을 보냈습니다.") + .data("{\"friendshipId\":" + friendship.getFriendshipId() + + ",\"requesterId\":\"" + requester.getUserId() + "\"}") + .build(); +``` + +**스마트 알림 관리**: +```java +// FriendshipService.java:111-117 +// 처리 완료 시 기존 알림 자동 읽음 처리 +notificationRepository.findByUser_UserIdAndTypeAndDataContaining( + userId, "friend_request", "\"friendshipId\":" + friendshipId) + .forEach(existingNotification -> { + existingNotification.setIsRead(true); + notificationRepository.save(existingNotification); + }); +``` + +### 5. 권한 기반 접근 제어 + +**세밀한 권한 검증**: +```java +// FriendshipService.java:86-89 +// 요청 수신자만 수락 가능 +if (!friendship.getAddressee().getId().equals(currentUser.getId())) { + throw new IllegalArgumentException("요청을 수락할 권한이 없습니다."); +} + +// FriendshipService.java:228-232 +// 친구 관계 당사자만 해제 가능 +if (!friendship.getRequester().getId().equals(currentUser.getId()) && + !friendship.getAddressee().getId().equals(currentUser.getId())) { + throw new IllegalArgumentException("친구 관계를 해제할 권한이 없습니다."); +} +``` + +### 6. 동적 친구 목록 조회 + +**유연한 관계 매핑**: +```java +// FriendshipService.java:204-208 +// 요청자/수신자 구분 없이 상대방 정보 반환 +User friend = friendship.getRequester().getId().equals(user.getId()) + ? friendship.getAddressee() // 내가 요청자면 수신자가 친구 + : friendship.getRequester(); // 내가 수신자면 요청자가 친구 +``` + +### 7. 입력 검증 및 예외 처리 + +**포괄적 검증**: +```java +// UserService.java:38-43 +if (request.getUserId() == null || request.getUserId().trim().isEmpty()) { + return new LoginResponse(false, "사용자 ID를 입력해주세요"); +} +if (request.getPassword() == null || request.getPassword().trim().isEmpty()) { + return new LoginResponse(false, "비밀번호를 입력해주세요"); +} +``` + +**자기 참조 방지**: +```java +// FriendshipService.java:34-37 +if (requester.getId().equals(targetUser.getId())) { + throw new IllegalStateException("자기 자신에게 친구 요청을 보낼 수 없습니다."); +} +``` + +## 성능 최적화 포인트 + +1. **인덱스 활용**: userId, friendshipId 기반 빠른 조회 +2. **배치 조회**: 친구 목록 일괄 조회로 N+1 문제 방지 +3. **상태 기반 필터링**: 데이터베이스 레벨에서 status 필터링 +4. **트림 처리**: 입력값 정규화로 중복 데이터 방지 + +## 확장성 고려사항 + +- **JWT 토큰**: 현재 userId 기반에서 JWT로 업그레이드 예정 +- **다중 디바이스**: FCM 토큰 배열로 확장 가능 +- **소셜 기능**: 친구 추천, 그룹 채팅 등 확장 기능 지원 +- **OAuth 연동**: 소셜 로그인 통합 가능한 구조 + +## 보안 고려사항 + +- **비밀번호 정책**: 복잡도 검증 추가 권장 +- **세션 관리**: 토큰 만료 및 갱신 메커니즘 도입 +- **Rate Limiting**: 친구 요청 스팸 방지 +- **개인정보 보호**: GDPR 준수를 위한 데이터 삭제 정책 + +이러한 설계를 통해 **보안성**, **확장성**, **사용자 경험**을 모두 고려한 견고한 소셜 네트워킹 플랫폼을 구축했습니다. \ No newline at end of file