분류 기술 Language Java 17 Framework Spring Boot 3.2.0 Security Spring Security + JWT (HttpOnly Cookie) Database PostgreSQL 15 (JPA / Hibernate) Cache Redis 7 (Lettuce) Real-time STOMP WebSocket, SSE API Docs Springdoc OpenAPI (Swagger UI) ID Generation TSID (hypersistence-utils) Config Encryption Jasypt Monitoring Micrometer + Prometheus Build Gradle 8.5 Container Docker + Docker Compose
┌─────────────────────────────────────────────────────────────┐
│ Cloudflare │
│ DNS · CDN · WAF · SSL/TLS │
└────────────────────────┬────────────────────────────────────┘
│ HTTPS / WSS
┌────▼────┐
│ Nginx │ :443 → :8080 / :8001
└────┬────┘
┌─────────────┼─────────────┐
│ │ │
┌──────▼──────┐ │ ┌──────▼──────┐
│ BE Server │ │ │ AI Worker │
│ Spring Boot │◄─────┘ │ FastAPI │
│ :8080 │◄────────────│ :8001 │
└──────┬──────┘ Callback └─────────────┘
│
┌──────┴──────┐
│ Data Layer │
│ PostgreSQL │
│ Redis │
└─────────────┘
도메인 구성 (Clean Architecture) domain/
├── auth # 인증·인가 (JWT, 토큰 재발급)
├── exam # 시험 세션 관리
├── submission # 코드 제출 · Outbox Poller
├── chat # AI 채팅 · 토큰 사용량
├── problem # 문제 CRUD
├── statistics # 통계 집계
└── admin # 관리자 · 마스터 운영
각 도메인은 ui → application → domain → infrastructure 레이어로 분리되며,
UseCase 단위로 비즈니스 로직이 구성됩니다.
src/main/java/com/yd/vibecode/
├── VibecodeApplication.java
├── domain/
│ ├── admin/ # 관리자 계정·보드·메트릭·시험 관리
│ ├── auth/ # 로그인·로그아웃·토큰 재발급
│ ├── chat/ # 채팅 저장·조회·AI 콜백
│ ├── exam/ # 시험 상태·참가자 세션
│ ├── problem/ # 문제 조회
│ ├── statistics/ # 통계
│ └── submission/ # 제출·스트리밍·내부 처리
└── global/
├── config/ # Web, JPA, Redis, WebSocket, Async
├── security/ # SecurityConfig, JWT, STOMP Interceptor
├── interceptor/ # JWT Blacklist, Cookie Handshake
├── swagger/ # API 명세 인터페이스
├── exception/ # 전역 예외 처리
├── annotation/ # @CurrentUser, @AccessToken 등
└── util/ # CookieUtils, SecureRandomGenerator
참가자 입장 — Entry Code + 이름 + 전화번호로 JWT 발급 (회원가입 불필요)관리자 로그인 — ID/PW 기반 Access Token + Refresh Token 발급토큰 저장 — HttpOnly 쿠키 전달 (XSS 방지)토큰 로테이션 — Refresh Token 재발급 시 기존 토큰 즉시 무효화블랙리스트 — 로그아웃된 Access Token을 Redis에 등록하여 재사용 차단STOMP 인증 우회 — WebSocket은 HttpOnly 쿠키 접근 불가 → body로 토큰 전달 후 StompPrincipalInterceptor에서 검증시험 생성·시작·종료 (관리자) 시험 상태 실시간 조회 (타이머 동기화) 참가자 세션 정보 조회 코드 드래프트 자동 저장 (PUT /api/exams/{id}/code-draft) 제출 접수 후 202 Accepted 즉시 응답 (비동기 처리) Outbox Poller 로 Redis 이벤트를 AI Worker에 전달AI 채점 완료 시 Callback 수신 (POST /api/callbacks/ai/**) 채점 결과를 SSE 스트림 으로 관리자에게 실시간 전송 STOMP WebSocket (/ws) — 시험 상태 변경 브로드캐스트SSE (/api/admin/submissions/{id}/stream) — 채점 진행 스트리밍참가자 채팅 메시지 저장 → AI Worker로 전달 대화 이력 조회 토큰 사용량 추적 및 제한 관리자 계정 CRUD, 입장 코드 생성·관리 실시간 참가자 현황 보드 제출 상세 조회 (루브릭·코드 포함) 시스템 메트릭, 활동 로그 플랫폼 전역 설정 (시험 시간, 토큰 제한, 데이터 보관 정책) Method Path 설명 권한 POST/api/auth/enter참가자 입장 (JWT 발급) Public POST/api/auth/admin/login관리자 로그인 Public POST/api/auth/admin/logout로그아웃 ADMIN POST/api/auth/admin/reissue토큰 재발급 Cookie GET/api/auth/me내 정보 조회 Any GET/api/exams/{id}/state시험 상태 조회 USER GET/api/exams/{id}/participants/me참가자 세션 조회 USER POST/api/exams/{id}/submissions코드 제출 (202) USER GET/PUT/api/exams/{id}/code-draft코드 드래프트 USER GET/api/submissions/{id}제출 상세 (본인) USER POST/api/chat/messages채팅 메시지 저장 USER GET/api/chat/history채팅 이력 조회 Any GET/api/problems문제 목록 조회 USER GET/api/admin/**관리자 전용 API ADMIN/MASTER POST/api/callbacks/ai/**AI 채점 결과 수신 Internal GET/api/admin/submissions/{id}/stream채점 결과 SSE ADMIN
Swagger UI — http://localhost:8080/swagger-ui/index.html
참가자 서버
│ │
├─ POST /api/auth/enter ──────►│
│ { entryCode, name, phone } │
│◄─────────────────────────────┤ Set-Cookie: accessToken (HttpOnly)
│ { accessToken } │ (body 포함: STOMP 인증용)
│ │
│ STOMP Connect │
├─ connectHeaders: { │
│ Authorization: Bearer ... │
│ } ──────────────────────────►│ StompPrincipalInterceptor 검증
│ │
관리자
│
├─ POST /api/auth/admin/login ─►│
│◄─────────────────────────────┤ Set-Cookie: accessToken, refreshToken (HttpOnly)
│ │
├─ POST /api/auth/admin/reissue►│ refreshToken 검증 + 로테이션
│◄─────────────────────────────┤ 새 accessToken, refreshToken 발급
ws://host/ws
SUBSCRIBE /topic/exams/{examId}/state
→ 시험 시작·종료·상태 변경 브로드캐스트
SUBSCRIBE /topic/exams/{examId}/submissions
→ 신규 제출 알림 (관리자 보드)
GET /api/admin/submissions/{submissionId}/stream
← data: {"status":"JUDGING","score":null}
← data: {"status":"COMPLETED","score":85}
← event: close
Java 17+ Docker & Docker Compose # 1. 인프라 기동 (PostgreSQL + Redis)
docker compose up -d
# 2. 애플리케이션 실행
./gradlew bootRun
# 서버: http://localhost:8080# Swagger: http://localhost:8080/swagger-ui/index.htmldocker build -t be-vibecodeeval .
docker run -p 8080:8080 be-vibecodeeval docker compose -f docker-compose.prod.yml up -d 변수 설명 예시 SPRING_DATASOURCE_URLPostgreSQL JDBC URL jdbc:postgresql://localhost:5432/ai_vibe_coding_testSPRING_DATASOURCE_USERNAMEDB 사용자명 postgresSPRING_DATASOURCE_PASSWORDDB 비밀번호 passwordSPRING_REDIS_HOSTRedis 호스트 localhostSPRING_REDIS_PORTRedis 포트 6379JWT_SECRETJWT 서명 키 (256bit+) your-secret-keyJWT_ACCESS_EXPIRATIONAccess Token 만료 (ms) 3600000JWT_REFRESH_EXPIRATIONRefresh Token 만료 (ms) 604800000JASYPT_ENCRYPTOR_PASSWORD설정 파일 암호화 키 jasypt-passwordAI_SERVER_URLAI Worker 주소 http://localhost:8001