Commit graph

126 commits

Author SHA1 Message Date
7184049186 썬데이 메이플 cron + 윈도우에 목요일 추가 (금요일 공휴일 대응)
금요일이 공휴일이면 목요일에 선공개되는 케이스 지원.

- cron 스케줄: 목/금 9시 ('0 9 * * 4,5')
- currentWeekFriday: 목요일이면 내일 금요일을 week_start 로 (이번 주 사이클로 흡수)
- isInSundayWindow: 목요일도 포함. 해당 주차 row 가 없으면 어차피 available: false

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:56:22 +09:00
928b46f13a 공지/업데이트 섹션 라벨에서 '메이플스토리' 접두 제거
NoticeWidget config 의 notice/update 라벨을 '공지사항' / '업데이트' 로 단축.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:53:58 +09:00
01bbbbd6af GlobalTooltip: delay 중 마우스 벗어나면 title 복원 안 되던 버그 수정
showFor 가 호출되면 title 속성을 즉시 제거하고 titleMap 에 저장한 뒤
setTimeout 으로 지연. 지연 중에 마우스가 벗어나 handleOut 가 호출되어도
triggerRef 는 아직 null 이라 hide() 가 title 을 복원하지 못해 해당 요소의
title 이 영구 제거되고 이후 [title] 선택자에 걸리지 않아 툴팁이 안 뜸.

- pendingRef 추가해 "delay 중 title 제거된 타겟" 추적
- hide / showFor / handleOver / handleOut 모두 pendingRef 고려해 복원
- 타이머 중 다른 타겟으로 이동 / 같은 타겟 반복 hover 케이스 처리

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 08:39:04 +09:00
2d52a1668f effectivelyMax '(MAX)' 텍스트도 진행 바와 같은 앰버(--progress-amber)로
isMax→red, effectivelyMax→amber, emerald→emerald 세 상태 모두 텍스트와
진행 바 색상이 정확히 일치.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:00:23 +09:00
67cefb49a7 만렙 심볼 성장치 'MAX' 텍스트를 진행 바와 같은 빨강으로
effectivelyMax '(MAX)' 는 기존 앰버 유지해서 진행 바 색과 일치.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:59:09 +09:00
7191ec7af7 심볼 진행 바: 만렙과 '만렙 도달 가능'을 색상으로 구분
- 만렙(isMax): 빨강 (--progress-red: #ef4444)
- 만렙 도달 가능(effectivelyMax, 성장치 초과): 기존 앰버 유지
- 그 외: 에메랄드

기존엔 두 상태 모두 앰버라 구분이 안 됐던 문제 해결.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:58:12 +09:00
3ef40e8111 심볼 계산기 주간퀘 계산 수정 + 일퀘 툴팁 문구 조정
- computeCompletion 에서 day 0(오늘)의 주간 지급 스킵. 주간퀘 획득 드롭다운
  값(0이 아닐 때)이 이미 '이번 주에 받은 수량'을 반영한다고 가정. 목요일이
  오늘이어도 day 1(다음 목요일)부터 누적 시작.
  별도 토글 없이 드롭다운 값만으로 해결.
- 일일 퀘스트 완료 토글 title 'oldgr 일퀘 완료 여부' → '금일 일일 퀘스트
  완료 여부' (표기 일관성)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:55:40 +09:00
281332ad14 보스 이미지 loading=lazy, decoding=async 추가
이전 revert 과정에서 함께 사라졌던 이미지 비동기 로딩 속성 복원.
애니메이션과 무관한 최적화이므로 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:49:45 +09:00
f845e74844 Revert "MapleStory 폰트 font-display: optional 로 override해 CLS 제거"
This reverts commit 6e2159cf67.
2026-04-22 00:47:33 +09:00
98b27a5fae 페이지 전환 애니메이션 전체 revert
유저 체감 개선이 확실치 않고 오히려 버벅임 느낌이 남아있어 관련 6개
커밋 (d1764de, 1344a2f, 48f43ec, f5c5c69, 670d8ab, f63c1e0) 을 git revert.
StaggerGroup 컴포넌트 제거, Feature/Admin 페이지의 Suspense 스피너 복원,
보스 리스트의 border 구조 원복.

prefetch(7ebfe4a), backdrop-blur 제거(669b358), font-display optional
(6e2159c) 은 애니메이션 무관한 최적화라 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:46:46 +09:00
f63c1e06c5 애니메이션을 translateY 대신 scale로 변경해 CLS 제거
Chrome DevTools의 레이아웃 변경 원인 분석 결과 애니메이션 × 3이 CLS 0.17의
주요 원인으로 지목됨. translateY 애니메이션을 레이아웃 변경으로 카운트하는
케이스가 있음.

- StaggerGroup: y:30 → scale:0.97 로 변경. scale/opacity는 compositor-only
  속성이라 layout/paint 없이 GPU만 사용
- BossCrystal 루트 애니메이션도 동일하게 scale 기반으로 변경
- 자식 motion.div에 will-change: transform, opacity 명시적 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:42:25 +09:00
669b358460 렌더 병목 2곳 제거: 헤더 backdrop-blur + 전역 배경 transition
프로미스나인과 비교 분석 결과 메이플에만 있는 두 가지 무거운 패턴.

- Layout 헤더의 backdrop-blur-md 제거하고 불투명 배경(var(--bg-from))으로
  교체. sticky 헤더 아래 컨텐츠가 애니메이션될 때마다 frosted glass
  필터를 매 프레임 재계산하던 비용 제거 (fromis_9는 shadow-sm만 사용).
- html/body/#root의 background-color/image 500ms transition 제거.
  테마 전환 부드럽게 하려는 의도였지만 범위가 전역이라 페이지 렌더
  성능 발목을 잡음. 테마 토글은 이제 즉시 전환.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:34:10 +09:00
6e2159cf67 MapleStory 폰트 font-display: optional 로 override해 CLS 제거
개발자도구 Performance 분석 결과 CLS 0.17로 레이아웃 이동이 큼. JSDelivr
Maplestory.css의 font-display: swap이 폰트 도착 시 텍스트 너비를 swap
시켜서 카드 애니메이션 중에 레이아웃 튀어 버벅임 발생.

- JSDelivr CSS 링크 제거하고 @font-face를 index.html에 직접 선언하며
  font-display: optional 로 변경
- woff2만 참조 (fallback 포맷 제거)
- cdn.jsdelivr.net preconnect 추가해 첫 방문 시에도 빠르게 시도

첫 방문 시: fallback(Noto Sans KR)으로 즉시 렌더, Maplestory가 100ms
내 도착하지 못하면 그대로 유지. 이후 캐시된 재방문부터는 정상 적용.
레이아웃 이동 0, 애니메이션 부드럽게 진행.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:29:39 +09:00
670d8abc12 보스 수익 계산기 카드 슬라이드업 애니메이션 복원 + GPU 힌트 강화
- initial y:30, duration 0.4 복원하되 will-change: transform, opacity
  명시해 GPU 레이어 승격 확실히
- delay 0.03초 추가해 첫 프레임 레이아웃 안정화 후 애니메이션 시작

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:26:14 +09:00
f5c5c6927e 보스 수익 계산기 초기 등장 끊김 완화
- BossCrystal 루트 애니메이션을 y 이동 없는 opacity fade (0.3s)로 단순화.
  외부 transform과 내부 stagger 애니메이션이 동시에 돌면서 합성 단계가
  겹치던 부하 제거
- will-change: opacity 힌트 추가해 GPU 레이어 승격 명시

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:22:42 +09:00
48f43ecc0b 보스 리스트 스태거 개선: 구분선 중복 제거 + 버벅임 완화
- 내부 row의 border-t/first:border-t-0 제거, 부모 divide-y로 통일
  (motion.div 래핑으로 first-child 판정이 어긋나 구분선 중복 생기던 문제)
- divide color는 divide-[var(--panel-border)]로 토큰 직접 지정
- stagger 파라미터 완화: yOffset 20→10, duration 0.3→0.25, 간격 0.04→0.03
  (동시 애니메이션/이미지 디코드 부담 감소)
- 보스 이미지에 loading=lazy, decoding=async 추가해 초기 프레임 블로킹 방지

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:19:13 +09:00
1344a2f7a9 StaggerGroup 파라미터를 프로미스나인 사이트와 동일하게 맞춤 + 보스 리스트 애니메이션
- StaggerGroup 기본값: y 30px / duration 0.4s / 간격 0.1s, default ease
  (프로미스나인 AlbumDetail 패턴과 일치)
- staggerDelay / yOffset / duration prop 받도록 커스터마이즈 가능
- BossCrystal fade-in 파라미터도 동일하게 맞춤
- BossSelector 보스 리스트에 StaggerGroup 적용 (항목 많으므로 간격 0.04s,
  y 20px, duration 0.3s 로 가볍게)
- CharacterPanel 은 Reorder.Group 드래그 로직과 충돌하므로 제외

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:16:56 +09:00
d1764dea94 feature 페이지 Suspense 스피너 제거 + 섹션 순차 페이드인 애니메이션
- FeaturePage / AdminFeaturePage의 Suspense fallback 스피너를 null로 변경
- components/common/StaggerGroup: 자식을 각 motion.div로 감싸 순차
  페이드인 (staggerChildren 0.07s, duration 0.35s, ease 0.22,1,0.36,1)
- Liberation(Genesis/Destiny), Symbol 페이지 root를 StaggerGroup으로 교체
- BossCrystal은 grid 레이아웃 특성상 root 전체를 motion.div로 감싸 fade-in
- hover prefetch와 함께 chunk 로드 시 깜빡임 없이 자연스럽게 등장

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:13:15 +09:00
7ebfe4a449 홈 메뉴 카드 hover 시 기능 페이지 chunk prefetch
React.lazy 로 분할된 feature 번들을 메뉴 카드 hover/focus 시점에 미리
fetch 해서, 클릭→네비게이션 시점에는 이미 로드되어 있도록 함.
Suspense 깜빡임(~0.5s) 제거.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:48:43 +09:00
ea9a6461f2 배포 모드 전환: 프로덕션 Dockerfile + docker-compose 재구성
- frontend/Dockerfile: 멀티스테이지 (node 빌드 → serve로 dist 정적 서빙).
  포트 5173은 그대로 유지해서 Caddy 설정 변경 불필요
- backend/Dockerfile: npm ci --omit=dev + npm start (node --watch 제거)
- docker-compose.yml: volumes/모듈 마운트 제거, build 기반으로 변경,
  restart: unless-stopped, NODE_ENV=production 추가
- .dockerignore 양쪽 추가해서 이미지에 node_modules/.git 제외

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:38:12 +09:00
66cafdb540 데드 코드 제거
- QUEST_BTBOSS_IMAGE_BASE 상수: 정의만 있고 아무데서도 참조 안 함
- DESTINY_CHAPTERS[].image 필드: 6개 항목에 있었지만 읽는 곳이 없음
  (ProgressBar/QuestSelector가 chapter.boss + '.webp' 패턴으로 파일명 생성)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:35:01 +09:00
c072cccf44 이미지 서비스 통합: boss-crystal/image.js 제거 + safeDelete 헬퍼 추가
- services/boss-crystal/image.js의 uploadBossImage/deleteBossImage는
  services/image.js의 convertAndUploadTo와 safeDelete로 대체 가능해서 제거
- services/image.js에 safeDelete(path) 헬퍼 추가 (삭제 실패해도 흐름을
  끊지 않고 warn 로그). 기존에 try/catch 인라인으로 흩어져있던 세 곳 통일
- routes/admin/boss-crystal.js에 BOSS_IMAGE_PREFIX 상수 인라인

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:33:58 +09:00
b3907ec48f 공용 상수 backend/constants.js로 추출
DIFFICULTIES(난이도 enum), PARTY_SIZE(1~6), SYMBOL_MASTER_LEVEL(2~99),
UPLOAD_FILE_SIZE_LIMIT(10MB)를 backend/constants.js로 추출하고 admin.js,
boss-crystal.js, symbol.js, BossDifficulty 모델에서 참조.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:31:43 +09:00
1ee3f19f4f 데스티니 해방 계산 로직 완성 + 완료일 색상 정리
- 포인트 이월(cascade), 남은 포인트, 예상 해방일 계산을 Destiny에 연결
  (computeCompletionDate에 bosses/monthlyBoss/makeEmptyConfig 파라미터 추가)
- loop 후에도 미달이면 정상 상태 주간 획득량으로 선형 외삽해서 날짜 반환.
  Genesis·Destiny 모두 적용 (제네시스도 낮은 설정에서 '미정' 떴던 버그 해결)
- 전체 초기화 버튼 + ConfirmDialog 데스티니에도 추가
- --genesis-date / --destiny-date 토큰 분리. 다크는 amber-300 / sky-400,
  라이트는 가독성을 위해 amber-500 / sky-500로 한 톤 어둡게

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:16:03 +09:00
ee30c87518 데스티니 주차별 계산 UI + 탭 라벨 변경
- WeeklyScheduler를 bosses/monthlyBoss/imageBase/makeEmptyConfig prop
  받도록 일반화 (월간 보스 없으면 관련 UI/락 전부 스킵)
- WeeklyDefault가 WeeklyScheduler에 props 전달, Destiny에서 주차별 모드
  주차 카드 확장/추가/삭제 + 보스 아바타 뱃지 표시 동작
- 탭 '단순 계산/주차별 계산' → '일반/주차별' (ConfirmDialog 문구 포함)
- 주간 보스 완료 토글 버튼에 title 툴팁 추가
- store: destiny 슬롯에 schedulerWeeks 추가, migrate v2로 기존 사용자 backfill

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:04:46 +09:00
99500d91af 데스티니 해방에 단순 계산 모드 주간 보스 설정 추가
WeeklyDefault/BossRow를 bosses/imageBase/hasScheduler prop 받도록 일반화.
데스티니 단순 계산 모드에서 8개 보스의 난이도·파티 인원·완료 상태를 설정할
수 있도록 구현. 주차별 계산은 플레이스홀더.

store에 destiny weekly 슬롯 추가하고 v1 migrate로 기존 사용자의 localStorage
backfill 처리.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:59:43 +09:00
d506c022ca 데스티니 해방에 현재 진행 상태 섹션 추가
QuestSelector를 chapters/imageBase prop 받도록 일반화한 뒤, Destiny에
시작 날짜/진행 중인 결전/현재 결의 입력 섹션 구현. 결의 입력 max는
20,000 (6챕터 요구량 15,000 여유 포함).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:55:16 +09:00
0448b0bfc8 해방 탭 상태 분리 (제네시스/데스티니 각각)
- Liberation.jsx를 탭 shell로 단순화하고 Genesis/Destiny 컴포넌트 분리
- liberationType을 store에 persist해 새로고침/재접속 후에도 마지막 탭 유지
- calcMode를 genesisCalcMode/destinyCalcMode로 분리해 무기별 독립 저장
- ProgressBar를 chapters/imageBase/completionColor prop 받도록 일반화
- Destiny 컴포넌트에 계산 모드 탭 + 진행 바 표시, 완료일 색은 sky blue
  (--destiny-date: 다크 #38bdf8 / 라이트 #0284c7)
- 데스티니 전용 슬롯(destinySimple/destinyWeekly)과 updateDestinySlot/
  resetDestinySlot 액션 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:03:52 +09:00
29fcb39eb3 데스티니 해방 데이터 추가 (하드코딩)
총 45,000 포인트, 8보스 포인트 풀 + 6결전 챕터. 이미지 base url은
liberation/destiny/{boss,quest} 참조. image1/image2 수치 기준.
칼로스는 인게임에 하드가 없어 chaos 70으로 매핑.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 18:54:28 +09:00
2911dfe3a8 해방 퀘스트 진행 바 색상을 테마별 흑백으로 단순화
기존 보라/빨강 2색에서 다크 테마는 흰색, 라이트 테마는 검정으로 통일.
1차/2차 구분은 동일 색상의 투명도(0.55 vs 1.0, 바는 0.25 vs 0.5)로만 주어
시각적 통일감을 확보.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 18:32:21 +09:00
dc48f57501 비활성 요소의 금지 커서 제거
index.css 의 전역 button:disabled { cursor: not-allowed } 규칙과 개별
컴포넌트의 disabled:cursor-not-allowed / cursor-not-allowed 클래스를 모두
제거해 비활성 상태에서 기본 화살표 커서를 유지한다. opacity 등 기존 시각
피드백은 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 17:59:19 +09:00
edbaaf09aa 심볼 계산기에 이벤트 스킬(보약) 일퀘 보너스 자동 반영
Nexon Open API의 character/skill(grade=0) 응답에서 '그란디스/아케인리버
일일퀘스트 완료 시 획득 심볼 N개 증가' 문구를 파싱해 심볼 타입별 보너스를
일퀘 획득량 기본값에 바로 합산한다.

skill_level 필드는 이벤트 스킬에 한해 실제 레벨이 아닌 1로 고정 반환되므로
심볼 증가 개수 → 레벨 역산 테이블로 실제 레벨을 복원한다. 입력창 hover 시
'기본 X + 보약 Y (메이플 스위츠 Lv.Z)' 툴팁으로 근거를 노출.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 01:03:29 +09:00
3a1d8a63ac 이미지 선택 다이얼로그의 카드 툴팁 제거
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:30:02 +09:00
5368764f85 전역 툴팁 매니저 도입 + 기존 Tooltip 간소화
- components/common/GlobalTooltip.jsx 신설
  * document 전역 이벤트 위임으로 [title] / [data-tooltip] 자동 감지
  * title 속성 일시 제거로 브라우저 기본 툴팁 억제, 포털 렌더
  * data-tooltip-placement / data-tooltip-delay 옵션 지원
  * scroll/resize/Escape/mousedown 시 자동 숨김
- Tooltip.jsx는 자식을 <span title=... data-...> 로 감싸는 단순 래퍼로 변경
- App.jsx 루트에 GlobalTooltip 마운트
- 이제 전 코드베이스의 title="..." 가 모두 커스텀 툴팁으로 렌더됨

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:23:32 +09:00
7fc04cf371 보스 목록 스크롤을 OverlayScrollbars로 교체 + 좌우 여백
- features/boss-crystal/pc/user/BossSelector.jsx:
  * 목록 스크롤을 기본 overflow-y-auto → OverlayScrollbarsComponent
  * 메인 바디와 동일한 os-theme-maple os-theme-dark 테마
  * 헤더와 목록 좌우에 8px씩 추가 여백 (스크롤바와 내용 간격)
  * 헤더 행과 목록 row의 컬럼 정렬이 어긋나지 않도록 동기

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:11:00 +09:00
be548879dc 이미지 관리 다이얼로그 UX 정리
- Modal 공용 컴포넌트에 열기/닫기 애니메이션 추가, 뒷배경 클릭 닫기 제거
- ImagePicker에 동일한 애니메이션 + 뒷배경 클릭 차단 적용
- ImagePicker 이미지 크기를 관리 페이지와 동일하게 (p-4 + w-full h-full object-contain)
- ImagePicker 하단 빈 pagination 영역이 차지하던 여백 제거 (조건부 렌더)
- 그리드 높이를 632px로 고정 + OverlayScrollbars (os-theme-maple) 스크롤
- overscroll-behavior: contain 으로 뒷 페이지 스크롤 전파 방지

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:03:10 +09:00
4720e33f26 썬데이 메이플 다이얼로그 UX 개선
- backdrop 폭/높이 100vw/100dvh 명시 → 뷰포트 하단까지 블러 적용
- 배경 스크롤 잠금 + OverlayScrollbars overscroll-behavior:contain
  → 다이얼로그 스크롤이 뒷 페이지로 전파되지 않음
- 다이얼로그 닫힘 exit 애니메이션 정상 동작 (AnimatePresence를 부모로 이동)
- '공식 공지 보기' 하단 링크 제거 → 우상단 외부 링크 아이콘 버튼 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:46:44 +09:00
18cc1855ac 썬데이 메이플 홈 배너 + 이미지 다이얼로그
- components/pc/SundayMapleBanner.jsx: 아이콘 + 라벨 버튼, 클릭 시 이미지 다이얼로그
- variant에 따라 '썬데이 메이플' / '스페셜 썬데이 메이플' 이미지 아이콘 사용
  (관리자 이미지 관리에서 업로드한 것)
- Home.jsx 상단에 배치 (금~일 available일 때만 렌더)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:31:16 +09:00
a94137bd4d 썬데이 메이플 자동 수집 백엔드
- sequelize 모델: sunday_maple (week_start/variant/image_url 등)
- services/sundayMaple.js: 이벤트 API 조회 + HTML 스크래핑 + rustfs 업로드 + DB 저장 공용 함수
- services/sundayMapleCron.js: 금요일 09:00 KST에 10초 간격 폴링 (최대 5분)
- routes/sunday-maple.js: GET /api/sunday-maple/current
  * 금/토/일만 available
  * DB 없으면 lazy fetch 시도 (cron miss 대비)
- 제목 파싱으로 normal/special variant 판별
- rustfs 경로: maplestory/sunday/{week_start}.png

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:30:30 +09:00
bc0c2b22f0 태블릿 전용 라우트 / 폴더 추가
- routes/tablet.jsx: 태블릿 placeholder
- App.jsx: isMobileOnly / isTablet / (그 외=PC) 3단 분기
- components/tablet/, pages/tablet/: 향후 태블릿 전용 컴포넌트·페이지 자리
- features/registry.js: tablet device 지원 (getTabletComponent 추가)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:07:31 +09:00
57715726b8 react-device-detect 도입 (PC / 모바일 라우트 분기)
- App.jsx: BrowserView / MobileView 로 분기 렌더
- 모바일 접속 시 routes/mobile.jsx (현재 '준비 중' placeholder) 렌더
- 구조 개편 후 실제 device 감지 활성화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:59:36 +09:00
0dd81b56e5 유틸리티 함수 단위 테스트 추가 (vitest)
- package.json: vitest 추가 + test/test:watch 스크립트
- utils/__tests__/formatting.test.js (7 tests)
- features/symbol/__tests__/utils.test.js (8 tests)
- features/liberation/__tests__/utils.test.js (18 tests)
- features/boss-crystal/pc/admin/__tests__/constants.test.js (6 tests)

총 39개 테스트 통과 (716ms)
- formatMeso / formatMesoKorean 경계 조건
- computeCompletion (심볼 완료 시뮬레이션)
- bossEarn, calcWeekPoints, calcDoneEarn, calcMonthlyEarn
- getSchedulerWeekRange (1주차/2주차, 목요일 시작 등)
- computeCompletionDate (단순 계산/주차별 계산 모드)
- 보스 결정 난이도 정의 및 스타일 헬퍼

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:41:48 +09:00
1646617069 리팩토링 6단계: Liberation 비즈니스 로직 utils.js로 추출 (458 → 299)
- features/liberation/utils.js 신설
  * bossEarn, calcWeekPoints, calcDoneEarn, calcMonthlyEarn
  * getSchedulerWeekRange
  * computeCompletionDate (파라미터로 state 주입받는 순수 함수)
- Liberation.jsx는 상태/렌더링/뷰모델만 담당 (299줄)
- WeeklyScheduler.jsx의 중복 bossEarn/calcWeeklySum/getWeekRange/makeEmptyWeek
  모두 utils에서 import (alias 유지)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:21:32 +09:00
4be648c21c 리팩토링 5단계: NoticeWidget.jsx 폴더로 분리 (431 → 4개 파일)
- components/pc/NoticeWidget/
  - index.jsx (38): 루트 + useQueries
  - config.js (62): SECTIONS 정의 + 날짜/배지 헬퍼
  - TextListSection.jsx (140): memo
  - CarouselSection.jsx (165): CardItem + memo

Home.jsx의 import 'components/pc/NoticeWidget'는 자동으로 index.jsx로 resolve

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:47:40 +09:00
569def6794 리팩토링 4단계: AdminImages.jsx 분리 (652 → 298 줄)
- components/common/Modal.jsx: 관리자 모달 공용 래퍼
- features/admin/pc/components/UploadModal.jsx (179줄)
- features/admin/pc/components/ImageCard.jsx (memo)
- features/admin/pc/components/Pagination.jsx
- AdminImages.jsx는 상태/mutations/렌더링 오케스트레이션만 담당

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:46:02 +09:00
1fe3ba0d12 리팩토링 3단계: Symbol.jsx 분리 (717 → 346 줄)
- features/symbol/utils.js: formatKoreanDate, computeCompletion, TYPE_ORDER
- features/symbol/pc/user/CharacterCard.jsx: 캐릭터 카드 (memo)
- features/symbol/pc/user/SymbolCard.jsx: 심볼 카드 (memo, 계산 로직 포함)
- Symbol.jsx: 검색/탭/그리드/요약 렌더링만 담당
- basicQueries/symbolQueries 배열을 useMemo로 감쌈 (매 렌더 재생성 방지)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:43:52 +09:00
f6f1e79b82 리팩토링 2단계: 성능 최적화 (메모화)
- SymbolCard / CharacterCard를 React.memo로 감쌈
  (심볼 그리드에서 형제 카드 변경 시 불필요 리렌더 방지)
- Liberation의 computeCompletionDate() 호출을 useMemo로 감쌈
  (520회 루프가 매 렌더마다 돌던 것을 관련 state 변경 시만 실행)
- Symbol.jsx의 로컬 formatMesoKorean 중복 정의 제거 (utils import)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:41:17 +09:00
c6ac3366cc 리팩토링 1단계: 공용 utils/FormField 추출
- utils/formatting.js 신설 (formatMeso, formatMesoKorean 통합)
- components/common/FormField.jsx 신설 (label+hint+error 공용 래퍼
  + formInputClass/formInputStyle 상수)
- 중복 정의 제거:
  * BossForm, SymbolForm, AdminMenuForm의 Field 로컬 정의 삭제
  * boss-crystal constants.js의 formatMeso → utils re-export
  * SymbolForm의 formatMesoKorean 로컬 정의 삭제
  * 3개 폼의 inputCls/inputStyle 상수 삭제

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:39:23 +09:00
4da16abc10 import path 깊이 수정
구조 개편 후 depth가 한 단계 깊어진 components/common, components/pc,
features/admin/pc/components 내부 파일들의 상대 import 경로 업데이트

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:37:15 +09:00
1ad25630bf 구조 개편 4단계: routes/ 신설 + App.jsx 단순화
- routes/pc.jsx: 기존 App.jsx의 Route 정의를 추출
- routes/mobile.jsx: 모바일 placeholder (준비 중 안내)
- App.jsx는 디바이스 분기 자리만 남김 (현재 PCRoutes만 렌더)
- react-device-detect 도입 준비 완료

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:27:24 +09:00