← 이력서로 돌아가기

Coinness - Web

Coinness 개발팀 · 2024.10 ~
React 18TypeScriptViteTanStack QueryReact RouterTailwindCSSRecharts

블록체인·투자 정보 플랫폼 Coinness의 프론트엔드 전반을 담당하며, 페이백(거래소 수수료 환급) 기능 개발부터 광고 운영, 성능·개발 생산성 개선까지 주도했습니다.

주요 역할 및 성과

페이백 기능 개발 (Payback)

예상 페이백 계산기

거래소 수수료 정책 기반 예상 환급금을 계산하는 웹/웹뷰 공용 화면으로, 비로그인 사용자도 접근 가능하도록 설계했습니다.

접근
  • useCalculatorForm(폼 상태·입력 핸들러, 사용자 입력값만 수집)과 useCalculatePayback(계산 수행 + 결과 화면 이동 트리거)으로 관심사 분리
  • paybackRate 소수 변환 및 헤더·결과 상단 노출값 반올림 처리 — 기획 변경에 따라 반올림 방식·노출 포맷을 유연하게 수정
결과
  • 계산 로직 재사용성과 기획 변경 대응력 확보
Web/WebView 상태 전달 통일
문제
  • 결과 페이지로 navigate하며 넘긴 location.state가, 웹뷰 브릿지(redirectWebAction)가 웹뷰를 다시 띄우는 과정에서 유실됨
해결
  • 상태값을 navigate 대신 queryString으로 전달해 웹뷰 재진입에도 값이 보존되도록 변경
결과
  • 웹·웹뷰에서 동일한 계산 플로우 보장
페이백 혜택·버프 페이지
구성
  • Hero·EventCardList·Banner 영역 구성
  • EventCard 클릭 시 AppBridge.redirectExternalURLAction로 외부 링크, 배너 클릭 시 거래소 상세 혜택으로 이동
리팩터
  • useBuffTable에서 JSX를 제거하고 순수 데이터를 반환하도록 데이터/프레젠테이션 분리
  • BenefitRate 공통 컴포넌트 추출
거래소 연동 및 유입 동선
문제
  • 앱스플라이어 딥링크가 앱은 열리나 지정 경로로 이동하지 않음
  • 앱 다운로드 원링크 QR이 구 앱스토어로 연결됨
해결
  • 딥링크를 URL 스킴으로 처리하고, 앱 다운로드 QR을 react-qr-code로 교체
  • 거래소 선택 페이지·혜택 배너 API 연동, OG 태그(title/description/og image) 적용

광고 노출 및 운영 (Ads)

AdSense 반응형 광고 CLS 방지
문제
  • AdSense가 부모 요소에 !important 인라인 스타일을 강제 주입해 레이아웃 점프(CLS) 유발
  • 반응형 배너는 부모에 명시적 width가 없으면 availableWidth=0 오류 발생
해결
  • MutationObserver로 스타일 변경을 감지해 레이아웃에 큰 영향을 주는 인라인 스타일만 제거
  • 반응형 배너 부모에 명시적 width 지정, height 고정 대신 min-height로 최소 영역 확보
Fill/No-fill 동적 감지
문제
  • no-fill(광고 없음) 시 빈 광고 영역이 남아 UX·레이아웃 저하
해결
  • useAdStatusObserver 커스텀 훅으로 data-ad-status(unfilled)를 추적
  • unfilled 시 해당 영역 자체를 비노출 처리
가상 스크롤 내 광고 최적화
문제
  • 가상 스크롤에서 광고가 viewport를 벗어나면 unmount→remount 발생
  • 애드센스가 매번 재요청되어 CTR/RPM 하락 및 계정 리스크
시도
  • overscan 확대, DOM KeepAlive → 실패
해결 (sticky portal)
  • 리스트 내부엔 광고와 동일 크기의 빈 spacer div만 배치
  • 광고 컴포넌트는 리스트 외부에 absolute로 독립 렌더링
  • position×virtualRowHeight + height로 top 좌표를 계산·동기화
결과
  • 스크롤 중 unmount·추가 요청 없이 최초 광고 유지
무한 스크롤 중복 광고 방지
문제
  • 동일 slotId에 반복 요청 시 애드센스가 기존 낙찰 광고를 재사용
해결
  • infeed_v1/v2/v3 등 slotId를 순환 교차 호출(슬롯 분할)
  • 중복 노출 감소 + 입찰 경쟁 활성화
Google Ad Manager 연동·마이그레이션
구현
  • defineOutOfPageSlot 전면 광고, BOTTOM_ANCHOR 앵커 광고 도입
  • 앵커 광고가 body에 주입하는 padding-bottom을 제거하는 훅으로 레이아웃 보정
  • AdSense 사이드·네이티브 슬롯을 GAM으로 마이그레이션
문제·해결
  • 인피드 no-fill 근본 원인이 오프스크린 슬롯 미파기 누적임을 파악 → 롤링 윈도우로 파기
보상형 광고 및 노출 실험

출석 보상 플로우에 보상형 전면 광고를 연동(no-fill 시 정상 진행)하고, Firebase Remote Config로 노출 위치·여부를 동적 제어하며 A/B 테스트·노출/클릭 이벤트 로깅을 운영했습니다.

개발 생산성 및 DX

문제
  • 언어팩을 개발자가 수동 MR로 반영해 충돌이 잦고 반복 작업 부담
해결
  • GitLab Schedule(매일 오전 10시, 주말 제외)로 chore/i18n 브랜치에 MR 자동 생성·최신화
  • 급할 땐 파이프라인 수동 변수로 임시 반영
결과
  • 수동 MR 생성 제거 및 언어팩 충돌 발생률 100% 감소
AI 코드 생성 자동화 (Custom Skills)
흐름
  • Swagger/OpenAPI → 컨벤션에 맞는 API 함수 생성(swagger-to-api)
  • → TanStack Query 훅·query key factory 생성(api-to-hook)을 /swagger 커맨드로 실행
확장
  • figma-to-code로 Figma 디자인 기반 UI 코드를 생성해 디자인 UI 작업 시간 단축
  • generate-story로 컴포넌트의 각 상태(state)별 케이스를 Storybook에 자동 반영
  • generate-test로 컴포넌트·로직 테스트 코드 생성
Knip 기반 데드코드 관리

미사용 파일·export·의존성을 자동 감지해 CI 아티팩트화하고, 레거시 혜택·출석 코드 등 실제 데드코드 제거에 활용했습니다.

개발 안전장치·컨벤션

보호 브랜치 로컬 커밋을 차단하는 pre-commit 훅, simple-import-sort 등 ESLint·Stylelint 표준화, CLAUDE.md 규칙을 1,179줄 → 405줄(66%↓)로 정리했습니다.

성능 및 사용자 경험 최적화

PnL 공유 이미지 생성 속도 87% 개선 (2.3s → 0.3s)
문제
  • html2canvas가 DOM→canvas 재드로잉에 2초 이상 소요, 번들 140KB
해결
  • modern-screenshot(25.4KB)로 교체 — DOM 직렬화→SVG 포장→canvas 렌더
  • 컴포넌트 마운트 완료 시점에 DOM→이미지 변환을 미리 실행해 다운로드 클릭 시 즉시 저장
추가 이슈
  • 배포 후 폰트·이미지 재요청 지연 → subset font(라틴·숫자·특수문자)만 base64로 임베딩, font-weight별 필요한 것만 유지
  • 깨지는 UI 일부는 SVG로 교체, QRCode 오류복원 레벨을 Q→L로 낮춰 인식률 개선
가상 스크롤

@tanstack/react-table·react-virtual 기반 독립 VirtualScroller를 만들어 지갑 내역·라이브·검색 등 대규모 목록에 적용, viewport 내 DOM만 유지하고 동적 ROW 높이 측정으로 스크롤 점프를 방지했습니다.

Prefetch·병렬 요청
문제
  • 대시보드 진입 시 선후관계 없는 요청들이 waterfall로 직렬 처리됨
해결
  • 선후관계 없는 요청을 useSuspenseQueries로 병렬화(컴포넌트당 useSuspenseQuery 하나 사용 구조로 정리)
  • Equity Chart에 query prefetch 적용
Optimistic UI·Debounce

useMarketBookmark의 onMutate 낙관적 업데이트와 onError 롤백, 즐겨찾기·구독 버튼 debounce로 과도한 API 요청을 방지했습니다.

Suspense·Error Boundary

속보 상세·커뮤니티 ProfitCard·모바일웹 홈을 섹션별 Suspense/ErrorBoundary로 분리하고, 서버 상태별 에러는 중앙 처리하도록 구성했습니다.

번들 최적화
교체
  • lodash → es-toolkit, lottie-web → lottie_light(eval 제거)
  • dynamic import 경고 수정으로 code splitting 정상화
청크·결과
  • Vite manualChunks로 도메인별 청크 분리(rollup-plugin-visualizer 활용)
  • 메인 번들 약 25%(4,752 → 3,033KB) 절감

제품 아키텍처 및 설계

React Router Data API 전환
목표
  • loader로 렌더 전 데이터 사전 로드, action+Form으로 낙관적 UI/리다이렉트/검증 일원화
  • lazy로 라우트 단위 코드 스플리팅, errorElement·전환 취소(AbortController)·자동 revalidation
방식
  • createBrowserRouter·createRoutesFromElements로 기존 트리를 유지하며 점진 마이그레이션
  • AppRouteLayout·RequireAuth·RouterContainer·RouterSideEffects로 인증·레이아웃·데이터 로딩 책임 분리
자산 변동 시계열 차트

recharts AreaChart 기반 누적 수익률(PnL) Equity Chart와 기간 필터(7D/30D/90D/180D)를 구현(XAxis 첫 날짜 누락 보정)하고, 대시보드에 TradingView 차트를 연동했습니다.

로케일 아키텍처

언어별 네비게이션 useGlobalNavigate를 useLocale(로케일 읽기)·useLocalizedNavigate(이동)로 분리하고 facade 패턴으로 점진 교체, SwitchCase로 언어별 렌더링을 통합했습니다.

상태·데이터 설계

query-key-factory로 queryKey를 팩토리화하고 모달 상태를 URL 쿼리로 관리(useQueryParams), 관심코인 편집 뷰를 discriminated union으로 모델링해 중첩 삼항·non-null 단언을 제거했습니다.

© 2026 dan.dev.log, All right reserved.

Built with NextJS