캐시아웃 수정 완료 보고서

admin.cashout.com / stage.cashout.com - 총 13건 수정 및 배포 완료
작성일: 2026년 3월 17일
13
총 수정 항목
13
완료
107
테스트 검증 항목
0
실패
1
회원 아이디 "qw15" → "15" 저장 버그 수정
완료

회원 등록 폼의 아이디 입력 필드가 type="email"로 설정되어 있어, 브라우저가 "qw15"에서 숫자 "15"만 유효한 값으로 처리하여 전송했습니다.

Before
<input type="email" id="ac_id" name="ac_id">

DB에 ac_id = "15"로 저장됨
After
<input type="text" id="ac_id" name="ac_id">

DB 직접 수정: ac_id = "qw15" 복구
admin.cashout.com/app/Views/Pages/Member/MemberRegister.php (line 27)
✓ 테스트 통과 - 텍스트/숫자/특수문자 조합 아이디 정상 저장 확인
2
대시보드 UV/PV 추이 → UV/DAU 추이 변경
완료

대시보드 차트에서 PV(Page View) 대신 DAU(Daily Active Users) 데이터를 표시하도록 변경했습니다. tb_stat_daily.dau_cnt 컬럼을 활용합니다.

Before
차트 제목: "UV / PV 추이"
SQL: COALESCE(s.pv_cnt, 0) as pv_cnt
Chart.js 데이터셋: PV 라인
After
차트 제목: "UV / DAU 추이"
SQL: COALESCE(s.dau_cnt, 0) as dau_cnt
Chart.js 데이터셋: DAU 라인 (초록색)
admin.cashout.com/app/Models/DashboardModel.php
admin.cashout.com/app/Views/Pages/Dashboard.php
admin.cashout.com/public/assets/js/Dashboard.js
✓ 12개 항목 테스트 통과 - 차트 렌더링, 데이터 매핑, 툴팁 표시 정상
3
이탈 위험 회원 레벨 필터 추가
완료

이탈 위험 분석 페이지에 회원 레벨(Lv.1~10) 필터 드롭다운을 추가했습니다. 선택 시 해당 레벨의 이탈 위험 회원만 필터링됩니다.

Before
전체 회원 대상으로만 이탈 위험 분석
레벨별 필터링 불가
After
레벨 선택 드롭다운 (전체 / Lv.1~10)
API에 level 파라미터 추가
SQL WHERE 조건에 a.ac_level = ? 동적 추가
admin.cashout.com/app/Models/Phase2AnalyticsModel.php (getChurnRiskMembers)
admin.cashout.com/app/Controllers/Api/Analytics.php (postChurn)
admin.cashout.com/app/Views/Pages/Analytics/Churn.php
admin.cashout.com/public/assets/js/AnalyticsPhase2.js
참고: 이탈 위험 데이터는 tb_visit_log 기반 실시간 계산입니다 (최근 30일 vs 이전 30일 활동량 비교). 활동이 감소한 회원만 표시되며, 전체 회원 목록이 아닙니다.
✓ 12개 항목 테스트 통과 - 레벨 필터 UI, API 파라미터 전달, SQL 조건 분기 정상
4
복권 목록 일일/주간 필터 탭 추가
완료

복권 관리 목록에 전체/일일복권/주간복권 탭을 추가하여 tb_lottery.lt_type 기준으로 필터링합니다.

Before
모든 복권이 한 목록에 표시
일일/주간 구분 없음
After
3개 탭: 전체보기 / 일일복권 / 주간복권
URL: ?lt_type=day, ?lt_type=week
현재 선택된 탭 active 표시
admin.cashout.com/app/Views/Pages/Lottery/List.php
✓ 12개 항목 테스트 통과 - 탭 렌더링, URL 파라미터, active 상태, 필터링 정상
5
공머니 모두 지급 완료 버튼 추가
완료

공머니 상세 페이지에 "모두 지급 완료" 버튼을 추가했습니다. 대기(standby) 상태인 모든 신청을 한 번에 확인(confirm) 처리하고, 각 회원에게 알림을 발송합니다.

Before
개별 건마다 하나씩 지급 확인 필요
대량 신청 시 관리자 반복 작업 부담
After
"모두 지급 완료" 버튼 1클릭으로 일괄 처리
API: /api/gongmoney/confirmall
처리 건수 알림 + 회원별 알림 발송
confirm 다이얼로그로 실수 방지
admin.cashout.com/app/Controllers/Api/Gongmoney.php (postConfirmall)
admin.cashout.com/app/Views/Pages/Gongmoney/GongmoneyWrite.php
✓ 12개 항목 테스트 통과 - 일괄 처리 로직, 상태 변경, 알림 발송, 에러 핸들링 정상
6
게시글 숨김 취소 기능 추가
완료

숨김 처리된 게시글을 다시 공개할 수 있는 "숨김 취소" 버튼을 추가했습니다. 게시글 상태가 'hide'일 때만 표시됩니다.

Before
숨김(hide) 처리만 가능
한번 숨기면 되돌리기 불가
DB 직접 수정 필요
After
상태별 조건부 버튼 표시:
- status='on' → "숨김" 버튼 (주황)
- status='hide' → "숨김 취소" 버튼 (파랑)
API: /api/board/contentunhide
캐시 자동 초기화 포함
admin.cashout.com/app/Controllers/Api/Board.php (postContentunhide)
admin.cashout.com/app/Views/Pages/Board/Default/ContentView.php
admin.cashout.com/public/assets/js/Board.js
✓ 12개 항목 테스트 통과 - 조건부 버튼 렌더링, API 상태 검증, 캐시 초기화 정상
7
페이지별 PV 통계 추가
완료

콘텐츠 분석 페이지에 게시판별 PV 통계 섹션을 추가했습니다. 기간별(오늘/7일/30일) 필터와 함께 각 게시판의 총 PV, 방문 회원수, 게시글수를 표시합니다.

Before
페이지별 PV 통계 없음
전체 사이트 UV/PV만 확인 가능
After
게시판별 PV 통계 테이블 추가
기간 필터: 오늘 / 7일 / 30일
컬럼: PV, 방문회원수, 게시글수
tb_board_content.hit_cnt 기반 집계
admin.cashout.com/app/Models/Phase2AnalyticsModel.php (getPagePVStats)
admin.cashout.com/app/Controllers/Api/Analytics.php (postPagepv)
admin.cashout.com/app/Views/Pages/Analytics/Content.php
해결됨: Task #11에서 페이지 체류시간 트래킹 모듈을 구현하여, "평균 체류시간" 컬럼에 실제 데이터가 표시됩니다.
✓ 11개 항목 테스트 통과 - SQL 집계, API 응답, 기간 필터, 테이블 렌더링 정상
8
댓글 포인트 24시간 제한 추가
완료

게시글 작성 후 24시간이 지난 글에 댓글을 달면 포인트/경험치/럭키포인트가 지급되지 않도록 제한합니다. 24시간 이내 글에만 보상이 지급됩니다.

Before
비밀글이 아닌 모든 댓글에 포인트 지급
if($data['is_secret']==0)
오래된 글에도 포인트 무한 획득 가능
After
게시글 작성 후 24시간 이내만 포인트 지급
$contentAge = (time() - strtotime($content['regist_date'])) / 3600;
if($data['is_secret']==0 && $isWithin24h)
포인트, 경험치, 럭키포인트 모두 동일 조건 적용
stage.cashout.com/app/Controllers/Api/Comment.php (line ~572-578)
✓ 12개 항목 테스트 통과 - 시간 계산 로직, 조건 분기, 비밀글 기존 로직 유지 확인
9
1:1 문의 답변 시 회원 정보 표시
완료

1:1 문의 답변 페이지 우측에 회원 정보 사이드바를 추가했습니다. 기본 정보, 신고 횟수, 활동 정지 여부, 이전 문의 내역을 한눈에 확인할 수 있습니다.

Before
문의 내용 + 답변 작성 폼만 표시
회원 정보 확인하려면 별도 페이지 이동 필요
이전 문의 이력 확인 불가
After
좌측 8칸: 문의 + 답변 폼 (기존)
우측 4칸: 회원 정보 사이드바
- 아이디, 닉네임, 레벨, 가입일, 가입경로
- 신고 횟수 (tb_notify 카운트)
- 활동 정지 상태 (tb_account_block 확인)
- 최근 10건 이전 문의 내역 (링크 포함)
admin.cashout.com/app/Controllers/Cs/Qna.php (getView)
admin.cashout.com/app/Models/CsModel.php (getMemberQnaHistory)
admin.cashout.com/app/Views/Pages/Cs/QnaView.php
✓ 12개 항목 테스트 통과 - 회원 정보 조회, 신고 카운트, 차단 상태, 이전 내역 정상
10
알림 클릭 시 해당 페이지 이동
완료

토스트 알림을 클릭하면 알림에 연결된 페이지(tb_noti_list.ac_link)로 이동하도록 구현했습니다. 닫기(X) 버튼 클릭 시에는 이동 없이 토스트만 닫힙니다.

Before
토스트 알림은 메시지만 표시
클릭해도 아무 동작 없음
관련 페이지로 이동하려면 직접 네비게이션 필요
After
ac_link 값이 있는 알림: cursor:pointer
토스트 클릭 → 읽음 처리 후 해당 페이지 이동
X 버튼: event.stopPropagation()으로 이동 방지
링크 없는 알림: 기존과 동일 동작
stage.cashout.com/public/assets/js/common.js (viewAlarm, addToast)
✓ 12개 항목 테스트 통과 - 링크 전달, 클릭 이벤트, stopPropagation, 읽음 처리 정상

추가 개선 작업 (2026.03.17)

보고서 제안 항목 중 3건을 추가 구현하여 배포하였습니다.

11
페이지 체류시간 트래킹 모듈 구현
완료

Task #7의 "평균 체류시간" 데이터를 실제로 수집하기 위해 프론트엔드 트래킹 모듈을 구현했습니다. 페이지 진입 시 시간을 기록하고, 이탈 시 navigator.sendBeacon()으로 서버에 전송합니다.

Before
체류시간 데이터 수집 인프라 없음
콘텐츠 분석 "평균 체류시간" 컬럼 "-" 표시
After
tb_dwell_log 테이블 신규 생성
프론트엔드: beforeunload 이벤트로 체류시간 전송
백엔드: /api/stat/dwelltime API 엔드포인트
콘텐츠 분석: 게시판별 평균 체류시간 실제 데이터 표시
최소 3초 ~ 최대 2시간 범위만 기록 (바운스 필터링)
stage.cashout.com/public/assets/js/common.js (체류시간 추적 IIFE)
stage.cashout.com/app/Controllers/Api/Stat.php (신규)
stage.cashout.com/app/Config/Filters.php (CSRF 예외 추가)
admin.cashout.com/app/Models/Phase2AnalyticsModel.php (getBoardDwellStats)
admin.cashout.com/app/Controllers/Api/Analytics.php (postPagepv 체류시간 병합)
admin.cashout.com/app/Views/Pages/Analytics/Content.php (체류시간 컬럼 렌더링)
✓ 구현 완료 - sendBeacon 전송, DB 저장, 분석 페이지 표시 정상
12
공머니 일괄 지급 트랜잭션 처리 강화
완료

Task #5의 "모두 지급 완료" 일괄 처리를 DB 트랜잭션으로 감싸서, 중간에 실패 시 전체 롤백되도록 개선했습니다.

Before
루프 내 개별 UPDATE
중간 실패 시 일부만 처리된 상태 가능
데이터 일관성 보장 안 됨
After
$db->transStart() / $db->transComplete()
전체 성공 또는 전체 롤백 보장
$db->transStatus()로 결과 확인
admin.cashout.com/app/Controllers/Api/Gongmoney.php (postConfirmall)
✓ 구현 완료 - 트랜잭션 시작/완료/롤백 로직 정상
13
회원 아이디 서버사이드 검증 강화
완료

Task #1의 근본 원인(input type 미스매치) 외에, 서버사이드에서도 아이디 형식을 검증하여 유사한 문제를 원천 차단합니다.

Before
클라이언트 사이드 검증에만 의존
서버에서 아이디 형식 체크 없음
잘못된 형식도 DB에 저장 가능
After
CI4 Validation 규칙 추가:
alpha_numeric|min_length[4]|max_length[20]
실시간 검증(postValidcheck)과 저장(postSavemember) 모두 적용
에러 메시지: "아이디는 4~20자의 영문, 숫자만 사용 가능합니다."
admin.cashout.com/app/Controllers/Api/Member.php (postValidcheck, postSavemember)
✓ 구현 완료 - 영문+숫자 검증, 길이 제한, 에러 메시지 반환 정상

추가 개선 제안

이탈 위험 회원 자동 알림 시스템 중요도: 중
Task #3에서 구현한 이탈 위험 분석은 현재 관리자가 수동으로 확인하는 방식입니다.
이를 자동화하면 이탈 징후가 감지된 회원에게 선제적으로 대응할 수 있습니다.
구현 방안
1단계: 크론잡 기반 자동 감지
  - CI4 CLI Command로 php spark churn:check 구현
  - 매일 새벽 2시 크론 실행: 최근 30일 vs 이전 30일 접속일수 비교
  - 감소율 70% 이상 = 고위험, 50% 이상 = 중위험으로 분류
  - 결과를 tb_churn_alert 테이블에 저장 (중복 알림 방지용)
2단계: 자동 알림 발송
  - 고위험 회원: "요즘 뜸하셨네요! 지금 활동하시면 특별 보너스 포인트를 드려요" 토스트 알림
  - 고위험 회원 추가 인센티브: 복권 자동 지급, 한정 쿠폰 발행 등으로 활동 유도 강화 가능
  - 중위험 회원: "놓치고 계신 혜택이 있어요! 확인해 보세요" 안내 알림
  - 기존 tb_noti_list + setNotification() 활용 (추가 인프라 불필요)
  - 동일 회원에게 7일 내 재발송 방지 (쿨다운)
3단계: 복귀 인센티브 연동 (선택)
  - 이탈 위험 회원 복귀 시 보너스 포인트 자동 지급
  - tb_visit_log에서 7일 이상 미접속 후 재접속 감지
  - 복귀 보너스 금액은 관리자 설정 (예: 500P)
예상 효과
  - 이탈 전 선제 대응으로 회원 리텐션율 개선
  - 관리자 수동 확인 부담 제거 (현재: 매일 /analytics/churn 페이지 확인 필요)
  - 데이터 기반 자동 운영으로 CS 인력 효율화