Amateurs는 프로그래머스 데브코스 수강생들을 위해 탄생한 차세대 커뮤니티 플랫폼입니다.
💡 단순한 정보 공유를 넘어, AI 기술로 개인화된 추천글을 제공하고,
실시간 소통으로 함께 성장하는 개발자 생태계를 구축합니다.
- 🤖 AI 맞춤 추천: 개인 관심사 기반 게시글 자동 큐레이션
- ⚡ 실시간 소통: WebSocket 채팅 & SSE 알림으로 즉각적인 커뮤니케이션
- 🔐 스마트 인증: OCR + AI 이미지 분석을 통한 자동 수강생 인증
- 📊 데이터 기반: 사용자 행동 분석을 통한 지속적인 UX 개선
graph TB
subgraph "Client Layer"
FE[Frontend]
Mobile[Mobile App]
end
subgraph "API Gateway"
LB[Load Balancer]
API[Spring Boot API]
end
subgraph "Application Layer"
Auth[Auth Service]
Post[Post Service]
AI[AI Service]
Chat[Chat Service]
end
subgraph "Data Layer"
MySQL[(MySQL)]
Redis[(Redis)]
MongoDB[(MongoDB)]
Qdrant[(Qdrant)]
end
subgraph "External Services"
S3[AWS S3]
Gemini[Google Gemini]
OCR[OCR Service]
end
FE --> LB
Mobile --> LB
LB --> API
API --> Auth
API --> Post
API --> AI
API --> Chat
Auth --> MySQL
Auth --> Redis
Post --> MySQL
Post --> Redis
Chat --> MongoDB
AI --> Qdrant
AI --> Gemini
API --> S3
API --> OCR
| 원칙 | 구현 방법 | 기대 효과 |
|---|---|---|
| 확장성 | 마이크로서비스 아키텍처, 이벤트 기반 설계 | 트래픽 증가에 유연한 대응 |
| 성능 | Redis 캐싱, JOOQ 최적화 쿼리 | 빠른 응답 속도 보장 |
| 안정성 | 트랜잭션 분리, 서킷 브레이커 패턴 | 장애 전파 방지 |
| 유지보수성 | Clean Architecture, 디자인 패턴 적용 | 코드 품질 및 생산성 향상 |
@Service
public class PostRecommendService {
@Autowired
private EmbeddingStore<TextSegment> embeddingStore;
public List<PostResponseDTO> recommendPosts(Long userId) {
UserProfile profile = aiProfileService.getProfile(userId);
List<EmbeddingMatch<TextSegment>> matches =
embeddingStore.findRelevant(profile.getEmbedding(), 10);
return matches.stream()
.map(this::convertToPostDTO)
.collect(toList());
}
} |
@MessageMapping("/chat/{roomId}")
public void sendMessage(@DestinationVariable String roomId,
@Payload DirectMessageRequest request) {
DirectMessageResponse response =
directMessageService.saveMessage(request);
messagingTemplate.convertAndSend(
"/topic/room/" + roomId, response);
// 실시간 알림 전송
sseService.sendAlarm(response.getReceiverId(),
createAlarm(response));
} |
|
OCR + AI 이미지 분석을 통한 완전 자동화된 인증 프로세스 sequenceDiagram
participant User
participant API
participant OCR
participant AI
participant DB
User->>API: 수료증 이미지 업로드
API->>OCR: 텍스트 추출 요청
OCR-->>API: 추출된 텍스트
API->>AI: 이미지 유사도 분석
AI-->>API: 유사도 점수 (0-100)
alt 점수 >= 80
API->>DB: 인증 승인
API-->>User: 인증 완료
else 점수 < 80
API-->>User: 인증 실패
end
|
|
# 전체 테스트 실행
./gradlew test
# 커버리지 리포트 생성
./gradlew jacocoTestReport
# 커버리지 검증 (최소 50% 요구)
./gradlew jacocoTestCoverageVerification- 정적 분석: SonarQube 연동
- 코드 리뷰: 모든 PR에 대해 최소 2명 승인 필요
src/main/java/kr/co/amateurs/server/
├── 📂 annotation/ # 커스텀 어노테이션
│ ├── alarmtrigger/ # 알람 자동 생성 AOP
│ └── checkpostmetadata/ # 게시글 메타데이터 검증
├── 📂 config/ # 설정 클래스
│ ├── auth/ # 인증/인가 설정
│ ├── jwt/ # JWT 처리
│ └── websocket/ # WebSocket 설정
├── 📂 controller/ # REST API 컨트롤러
├── 📂 domain/ # 도메인 모델
│ ├── dto/ # 데이터 전송 객체
│ ├── entity/ # JPA 엔티티
│ └── enums/ # 열거형 상수
├── 📂 repository/ # 데이터 접근 계층
│ └── [domain]/ # 도메인별 Repository
├── 📂 service/ # 비즈니스 로직
│ ├── ai/ # AI 관련 서비스
│ ├── alarm/ # 알람 시스템
│ └── [domain]/ # 도메인별 서비스
└── 📂 utils/ # 유틸리티 클래스
| 패턴 | 적용 위치 | 목적 |
|---|---|---|
| Strategy | AlarmCreator, CommentQueryStrategy |
알고리즘 전략 분리 |
| Factory | ReportTargetHandlerFactory |
객체 생성 책임 분리 |
| Observer | Event-Driven Architecture | 느슨한 결합을 통한 확장성 |
| Template Method | BaseEntity, BaseService |
공통 로직 추상화 |
| Registry | AlarmCreatorRegistry |
타입별 처리기 중앙 관리 |
- 📖 API 문서 - Swagger UI
- 🎯 코딩 컨벤션 - 개발 표준 가이드
- 🗄️ 데이터베이스 가이드 - DB 설계 원칙
- ⚡ JOOQ 가이드 - 타입 안전 SQL 작성법




