멘토 화면의 '분석·기수관리'를 개인 카드 나열에서 '묶어서 본 그림'으로 끌어올림.
기수(코호트):
- Flyway V2 마이그레이션으로 student_profile.cohort 추가(기존 학생 '2026' 백필)
- 가입 시 현재 기수(app.current-cohort, .env로 매년 변경) 자동 배정
- 명단에 기수 컬럼 + 배지 클릭으로 변경(POST /mentor/students/{id}/cohort)
- CSV 내보내기·StudentProfileResponse에 기수 포함
분석 대시보드(GET /mentor/analytics?cohort=):
- MentorAnalyticsService: 코호트별 KPI(진도·퀴즈·코딩·리뷰대기),
학생별 마지막 활동 계산(4개 테이블 타임스탬프 max), 관심필요(7일+ 미활동),
어려운 지점(평균 낮은 퀴즈·통과율 낮은 코딩 top5)
- MentorAnalytics 컴포넌트: 기수 선택·KPI 카드·관심필요·핫스팟, 슬러그→제목 해석
테스트: 백엔드 47→51(분석 4), 프론트 27→30(분석 3).
운영 검증: V2 빈DB→운영 무손실 적용(3명 백필), 분석 API·대시보드 브라우저 확인, 스모크 11/11.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
4.2 KiB
YAML
71 lines
4.2 KiB
YAML
# 미림 수습 학습 플랫폼 설정
|
|
# 학습 포인트: 설정값은 코드에 안 박고 여기(그리고 환경변수)에 둡니다.
|
|
# ${환경변수:기본값} — 환경변수가 있으면 그 값을, 없으면 기본값(로컬 개발용)을 씁니다.
|
|
spring:
|
|
application:
|
|
name: mirim-backend
|
|
datasource:
|
|
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:mirim}
|
|
username: ${DB_USER:mirim}
|
|
password: ${DB_PASSWORD:mirim123}
|
|
jpa:
|
|
hibernate:
|
|
# 학습 포인트: 이제 스키마는 Flyway가 소유한다. Hibernate는 validate로 "엔티티와 실제
|
|
# 테이블이 일치하는지 검증"만 하고, 테이블을 만들거나 바꾸지 않는다.
|
|
# - update였을 때의 문제(컬럼 삭제 미반영·변경 이력 없음·조용한 드리프트)를 끝낸다.
|
|
# - 엔티티를 바꿨는데 마이그레이션(Vn.sql)을 안 쓰면 validate가 기동 시 실패해 알려 준다
|
|
# → "엔티티와 DB를 함께 바꿔라"를 기계가 강제한다.
|
|
ddl-auto: validate
|
|
# open-in-view: 화면 렌더링이 끝날 때까지 DB 커넥션을 물고 있는 기능. REST API 서버에선
|
|
# 커넥션 낭비일 뿐이라 끈다. (끄면 LAZY 로딩은 반드시 @Transactional 안에서 끝내야 한다)
|
|
open-in-view: false
|
|
properties:
|
|
hibernate:
|
|
format_sql: true
|
|
# Flyway — DB 스키마 마이그레이션(버전 관리). classpath의 db/migration/V*.sql을 순서대로 적용.
|
|
flyway:
|
|
# 학습 포인트: baseline-on-migrate —
|
|
# 이미 테이블이 있는(비어있지 않은) 기존 운영 DB엔 V1을 "실행"하지 않고 "이미 반영됨"으로
|
|
# 표시(baseline)만 한다. 안 그러면 V1의 CREATE TABLE이 "이미 존재"로 터진다.
|
|
# 빈 DB(신규/개발)에선 baseline이 일어나지 않고 V1부터 정상 실행돼 스키마를 만든다.
|
|
# → 같은 마이그레이션 파일로 "기존 운영 DB 편입"과 "신규 DB 생성"을 모두 안전하게 처리.
|
|
baseline-on-migrate: true
|
|
baseline-version: 1
|
|
|
|
# 앱 도메인 설정
|
|
app:
|
|
# 지금 가입하는 학생이 편입될 기수(코호트). 새 기수를 받을 땐 운영 .env에서 이 값만 바꾼다.
|
|
current-cohort: ${CURRENT_COHORT:2026}
|
|
|
|
server:
|
|
port: 8080
|
|
error:
|
|
# 학습 포인트: 스프링 기본값은 에러 응답에 message를 "안 싣는" 것이다(never).
|
|
# 우리는 ResponseStatusException에 한국어 사유("이미 사용 중인 아이디입니다" 등)를
|
|
# 정성껏 담는데, 이 설정이 없으면 그 문구가 클라이언트에 전달되지 않아
|
|
# 프론트의 err.response.data?.message가 항상 undefined였다(사용자는 두루뭉술한
|
|
# 폴백 문구만 봄). always로 켜서 서버가 쓴 안내가 화면까지 닿게 한다.
|
|
# 주의: 예외 메시지가 노출되므로, 예외에는 내부 정보(SQL, 경로 등)를 담지 말 것.
|
|
include-message: always
|
|
servlet:
|
|
session:
|
|
timeout: 8h # 하루 근무 동안 로그인 유지
|
|
cookie:
|
|
# 학습 포인트: 세션 쿠키에 붙이는 3대 보안 플래그. 세션 방식 인증에선 필수다.
|
|
http-only: true # JS(document.cookie)로 못 읽는다 → XSS로 세션 탈취 방어
|
|
secure: ${COOKIE_SECURE:false} # HTTPS로만 쿠키 전송(운영은 true). 로컬(http)은 false여야 로그인됨
|
|
same-site: strict # 다른 사이트에서 온 요청엔 쿠키를 안 붙인다 → CSRF 방어의 핵심
|
|
|
|
# 텔레그램 알림 (TelegramNotifier) — 학생 가입·제출을 멘토 텔레그램으로.
|
|
# 학습 포인트: 둘 다 비어 있으면 알림 기능이 통째로 꺼진다. 로컬 개발에선 아무것도
|
|
# 설정하지 않아도 앱이 그대로 돈다 — "설정이 없으면 기능이 꺼지는" 안전한 기본값 설계.
|
|
# 실제 토큰은 운영 서버 .env에만 둔다(절대 git에 넣지 않는다!).
|
|
telegram:
|
|
bot-token: ${TELEGRAM_BOT_TOKEN:}
|
|
chat-id: ${TELEGRAM_CHAT_ID:}
|
|
|
|
logging:
|
|
level:
|
|
# 학습 포인트: 개발은 DEBUG로 자세히, 운영은 INFO로. 로그도 자원이고, 과한 로그는 비용·노이즈다.
|
|
dev.awesomedev.mirim: ${LOG_LEVEL:DEBUG}
|