사이트픽 블로그
← 목록으로

개발일지 2026-06-28

엠포레 피아노학원 플랫폼 개발일지 (2026-06-28)

개요

오늘은 크게 세 가지 축으로 작업했다. 첫째, 세션 관리 완성 — JWT에 sessionId를 심어 세션 종료 시 즉시 인증을 차단하고, 중복 세션 정책(ON/OFF)과 자동 로그아웃을 구현했다. 둘째, 모니터링 고도화 — 더미 데이터를 걷어내고 실제 시스템 메트릭(CPU/메모리/디스크/DB풀/서비스 핑)을 수집하는 API를 만들었다. 셋째, 콘텐츠 관리(공지/FAQ/팝업) 와이어프레임 반영 — 셀렉트박스, 공개 여부, 노출 대상, 일괄 삭제 등 실무 기능을 추가했다. 그 외에 감사 로그 무한 스크롤, 환불 관리 신규 개발, 스케줄러 카카오 예약발송 등 다양한 화면을 손봤다.


수정/생성 파일 목록

백엔드 (piano-backend)

파일구분요약
admin/monitoring/MonitoringController.java신규GET /admin/monitoring API
admin/monitoring/MonitoringData.java신규리소스/서비스/통계 DTO
admin/monitoring/MonitoringService.java신규CPU·메모리·디스크·HikariCP·DB핑·뿌리오DNS 수집
admin/monitoring/MonitoringMapper.java신규일일 통계 쿼리 인터페이스
mapper/MonitoringMapper.xml신규api_audit_logs/admin_sessions 집계 SQL
admin/refund/RefundController.java신규환불 CRUD + 승인/반려 API
admin/refund/RefundService.java신규환불 비즈니스 로직
admin/refund/RefundMapper.java신규환불 매퍼 인터페이스
admin/refund/RegistrationRefund.java신규환불 엔티티
admin/refund/dto/RefundRequest.java신규환불 등록 DTO
admin/refund/dto/RefundProcessRequest.java신규승인/반려 DTO
mapper/RefundMapper.xml신규환불 검색/통계/승인/반려 SQL
migration-20260628-refunds.sql신규registration_refunds 테이블 + 공통코드
migration-20260628-popup-type-memo.sql신규팝업 memo 컬럼 + SCHEDULED 상태
migration-20260628-notice-faq-enhance.sql신규공지 노출 시작/종료/대상/알림톡, FAQ visible
admin/popup/Popup.java수정memo 필드 추가
admin/popup/PopupRequest.java수정memo 파라미터 추가
mapper/PopupMapper.xml수정memo 매핑/INSERT/UPDATE 반영
publicsite/announcement/Announcement.java수정startAt/endAt/targetScope/autoAlimtalk/status 추가
mapper/AnnouncementAdminMapper.xml수정신규 필드 매핑
student/faq/Faq.java수정visible 필드 추가
mapper/FaqAdminMapper.xml수정visible 매핑
admin/faq/dto/FaqRequest.java수정visible 파라미터 추가
audit/ApiAuditLogController.java수정offset/limit 페이징 파라미터
audit/ApiAuditLogMapper.java수정페이징 파라미터
audit/ApiAuditLogService.java수정페이징 전달
mapper/ApiAuditLogMapper.xml수정LIMIT/OFFSET 동적 쿼리
common/ErrorCode.java수정BAD_REQUEST 추가
admin/messagelog/MessageScheduler.java수정카카오 알림톡 예약 발송 추가

프론트 (piano-academy/admin)

파일구분요약
api/monitoring.ts신규모니터링 API 클라이언트
api/refunds.ts신규환불 API 클라이언트
api/schedulers.ts신규스케줄러 API 클라이언트
pages/Monitoring.tsx전면 재작성실 데이터 연동 + 30초 카운트다운 + 데이터 소스 테이블
pages/MembershipRefunds.tsx전면 재작성와이어프레임 기반 환불 관리 (필터/KPI/승인·반려)
pages/Schedulers.tsx전면 재작성더미→실 API 연동 + 활성/비활성 토글
pages/AuditLogs.tsx수정무한 스크롤 (IntersectionObserver) + 엑셀 비활성화
pages/Popups.tsx전면 재작성제목 링크 + 체크박스 일괄 삭제 + 액션 컬럼 제거
pages/Faqs.tsx수정공개 Chip + 질문 링크 + 체크박스 일괄 삭제
pages/Notices.tsx수정제목 링크 + 체크박스 일괄 삭제
pages/Roles.tsx수정전체 필터 'ALL' + 순서 컬럼 제거
pages/FreePolicies.tsx수정로딩 중복 제거
pages/MarketingPlans.tsx수정로딩 중복 제거
pages/MembershipPlans.tsx수정로딩 중복 제거
popups/popups/PopupForm.tsx전면 재작성와이어프레임 반영 (노출상태/우선순위/메모/안내)
popups/faqs/FaqForm.tsx수정카테고리 셀렉트 + 공개 여부 토글
popups/notices/NoticeForm.tsx수정노출 대상/시작/종료/알림톡 토글
api/auditLogs.ts수정offset/limit 파라미터
api/popups.ts수정memo + 일괄 삭제
api/faqs.ts수정visible + 일괄 삭제
api/announcements.ts수정신규 필드 + 일괄 삭제
components/Sidebar.tsx수정하위 없는 항목 '-' 표시, 중메뉴 볼드

상세 설명

1. 모니터링 실 데이터 연동

더미 하드코딩이었던 모니터링 화면을 실제 시스템 메트릭으로 교체했다.

백엔드 수집 방식:

// CPU: OS 로드 평균 / 코어 수
double loadAvg = os.getSystemLoadAverage();
int cpuPercent = (int) Math.min(100, (loadAvg / availableProcessors) * 100);

// 메모리: JVM 힙
long usedMem = runtime.totalMemory() - runtime.freeMemory();
int memPercent = (int) ((usedMem * 100) / runtime.maxMemory());

// DB 풀: HikariCP MXBean
if (dataSource instanceof com.zaxxer.hikari.HikariDataSource hds) {
    poolActive = hds.getHikariPoolMXBean().getActiveConnections();
}

프론트 30초 카운트다운:

const [countdown, setCountdown] = useState(30);
useEffect(() => {
  const tick = setInterval(() => {
    setCountdown((prev) => {
      if (prev <= 1) { load(); return 30; }
      return prev - 1;
    });
  }, 1000);
  return () => clearInterval(tick);
}, [load]);

useEffect cleanup으로 clearInterval을 하기 때문에 페이지 이탈 시 타이머가 정리된다.

2. 환불 관리 (03-4) 신규 개발

와이어프레임 기반으로 등록비 환불 관리를 처음부터 구축했다.

  • registration_refunds 테이블 + 공통코드 (refundStatus/refundChannel/paymentMethod/refundMethod/refundReason)
  • 검색 필터: 상태/항목/기간(일/주/월)/학원명
  • KPI 통계: 처리 대기, 월 환불 건수, 월 환불액, 평균 처리 시간
  • 승인/반려: POST /admin/refunds/{id}/approve, POST /admin/refunds/{id}/reject

3. 감사 로그 무한 스크롤

기존 500건 고정 로드 → 200건씩 무한 스크롤로 변경.

// IntersectionObserver로 하단 감지
const observer = new IntersectionObserver(
  ([entry]) => { if (entry.isIntersecting) fetchMore(); },
  { rootMargin: '200px' },
);
observer.observe(sentinelRef.current);

백엔드는 offset/limit 파라미터를 받아 LIMIT #{limit} OFFSET #{offset}으로 처리.

4. 콘텐츠 관리 와이어프레임 반영

공지 (06-1):

  • 노출 대상: 전체 학원 / 특정 학원 셀렉트
  • 노출 시작/종료: datetime + 상시(종료일 없음) 옵션
  • 발행 시 알림톡 자동 발송 토글
  • 임시저장/취소/발행 3버튼

FAQ (06-3):

  • 카테고리: 텍스트 입력 → 공통코드 셀렉트 (결제/구독/수업/계정/기타)
  • 공개/비공개 토글 버튼 (ToggleButtonGroup)

팝업 (06-2):

  • 노출 상태: 활성/비활성 → 노출/예약/대기 3단계
  • 노출 우선순위 + 내부 메모 필드 추가
  • 이미지 권장 사이즈 가이드 안내

공통 패턴 — 목록 페이지 체크박스 일괄 삭제:

<DataTable
  columns={columns}
  rows={rows}
  rowKey="id"
  selectable
  onSelectionChange={setSelected}
/>
// 선택 시 상단에 "N개 삭제" 버튼 표시

5. 스케줄러 카카오 예약발송

MessageScheduler의 TODO였던 카카오 알림톡 예약 발송을 구현:

} else if ("ALIMTALK".equals(msg.getChannel())) {
    ppurioService.sendKakao(
        msg.getRecipientPhone(), "@m포레", msg.getTemplateCode());
}

6. 사이드바 메뉴 개편

  • 매출/정산 하위에 중메뉴 4개 생성 (결제·정산 / 멤버십 구독 / 마케팅 / 분석)
  • 하위 메뉴가 없는 항목(실제 화면)은 아이콘 대신 -로 표시
  • 중메뉴: 폰트 볼드 + 들여쓰기 조정 (depth 1: pl 4→3)

트러블슈팅

HikariCP 패키지명 오타

모니터링 서비스에서 com.zaxxara.hikari로 import했으나 실제는 com.zaxxer.hikari. 빌드 에러로 발견 → 즉시 수정.

로딩 프로그레스바 2개 표시

fx.isLoadingbar(true) (글로벌) + <CircularProgress /> (페이지 내부) 두 개가 동시에 떴다. 내부 로딩을 return null로 교체하여 글로벌 로딩바만 사용.

SSH 터널 끊김

장시간 작업 중 SSH 터널이 끊어져 백엔드 기동 시 Communications link failure 발생. nc -z localhost 3306으로 확인 후 터널 재연결.


DB 마이그레이션 (오늘 적용)

파일내용
migration-20260628-refunds.sqlregistration_refunds 테이블 + 환불 관련 공통코드 5그룹
migration-20260628-popup-type-memo.sqlpopups.memo + popupStatus SCHEDULED
migration-20260628-notice-faq-enhance.sqlannouncements 5개 컬럼 + faqs.visible + 공통코드

진행률 업데이트

화면변경
08-2 모니터링0% → 100%
08-3 스케줄러 현황90% → 100%
09-1 계정 관리40% → 100%
09-2 권한 설정55% → 100%
09-3 감사 로그50% → 100%
09-5 약관 관리50% → 100%
09-5-1 약관 버전 등록0% → 100%
03-4 환불 관리0% → 85%

결론

시스템 운영 메뉴(모니터링/스케줄러/감사 로그/세션/권한/약관/계정)가 모두 100%에 도달했다. 콘텐츠 관리(공지/FAQ/팝업)도 와이어프레임에 맞춰 실무 기능(노출 대상, 공개 여부, 일괄 삭제)을 갖추었고, 환불 관리도 백엔드+프론트 모두 신규 구축했다. 결제 모듈은 KSNET PG를 사용할 예정이며, 테스트 가맹점 키 발급 후 연동 개발을 진행할 계획이다.

댓글 1

  • test2026년 6월 29일

    ttt