Skip to content

SideProjectSFY/cloneNovaFE

Repository files navigation

CLONENOVA

React + NestJS(BFF) Frontend Platform 🎮⌨️

TypeScript | GraphQL BFF | Strapi Backend Integration | Monorepo | E2E Testing

React NestJS TypeScript GraphQL Strapi Playwright


프로젝트 소개

CloneNOVACodeNOVA 프로젝트를 계승한 React + NestJS(BFF) 기반 프론트엔드 프로젝트입니다.

Strapi Headless CMS를 백엔드 대용으로 활용하여 통합 E2E 테스트를 진행하였으며, TurboRepo 기반 Monorepo로 구성되었습니다.

프로젝트 정보

  • 프로젝트명: CloneNOVA
  • 기간: 2025.10 - 2025.11
  • 스택: React 19 + NestJS(BFF) + Strapi + TypeScript + GraphQL + Playwright
  • 아키텍처: Monorepo (TurboRepo)

프로젝트 목표

  • React 19 + NestJS(BFF) 기반 프론트엔드 개발: GraphQL을 활용한 현대적인 프론트엔드 아키텍처
  • TypeScript 마이그레이션: JavaScript에서 TypeScript로 전체 코드베이스 완전 전환
  • GraphQL BFF 패턴: Client-BFF 간 GraphQL 통신, BFF-Backend 간 REST API 통신
  • Strapi를 백엔드 대용으로 활용:
    • 빠른 프로토타이핑과 테스트를 위한 Headless CMS 백엔드
    • 향후 Spring Boot로 마이그레이션 예정
  • Monorepo 구조 (TurboRepo): 효율적인 패키지 관리 및 빌드 최적화
    apps/
      web/     (React Frontend - GraphQL Client)
      bff/     (NestJS Backend for Frontend - GraphQL Server + REST Client)
      strapi/  (Strapi Headless CMS - Backend 대용)
    backend/
      (Spring Boot - RESTful API Server - Future Migration)
    packages/
      shared-types/
      ui-components/
      utils/
    
  • 성능 최적화: React 최적화 패턴을 활용한 키보드 입력 무한 리렌더링 방지
  • 통합 E2E 테스트: Playwright를 활용한 Frontend(React) + BFF(NestJS) + Backend(Strapi) 통합 테스트
  • TypeScript를 통한 타입 안정성 확보
  • Panda CSS를 활용한 제로 런타임 스타일링
  • 데이터베이스 연동 및 CRUD 기능 구현
  • OAuth 및 PortOne(결제 API) 연동 실습
  • Redis 캐싱 및 실시간 랭킹 시스템
  • Apollo Client를 활용한 상태 관리 및 캐싱

핵심 작업

1. TypeScript 마이그레이션 (JS → TS)

100% TypeScript 코드베이스 엄격한 타입 체크 적용

  • 모든 프론트엔드 컴포넌트를 .tsx로 마이그레이션, 적절한 인터페이스 정의
  • BFF 서비스 및 리졸버 완전 타입화
  • 앱 간 타입 안정성을 위한 shared-types 패키지
  • 타입 안전한 쿼리를 위한 GraphQL 스키마 자동 생성

2. GraphQL BFF 아키텍처

최적의 데이터 페칭을 위한 현대적 3계층 아키텍처

  • Frontend → BFF: GraphQL (Apollo Client) - 유연한 쿼리
  • BFF → Backend: REST API (axios) - 안정적인 서버 간 통신
  • 장점: 타입 안정성, 효율적인 데이터 로딩, 단일 엔드포인트
Frontend (React + Apollo Client)
    ↓ GraphQL Queries/Mutations/Subscriptions
BFF (NestJS + Apollo Server)
    ↓ REST API calls (axios)
Backend (Strapi/Spring Boot REST API)

3. Strapi를 백엔드 대용으로 활용

빠른 프로토타이핑 및 통합 테스트를 위한 Headless CMS 백엔드

  • Content Type에서 자동 생성되는 REST API로 백엔드 대용
  • 로컬 개발용 SQLite, 프로덕션용 MySQL 지원
  • 8명의 사용자, 12개의 게임 기록, 7개의 결제 데이터 포함 Mock 데이터 로더
  • BACKEND_TYPE 환경 변수를 통한 Strapi ↔ Spring Boot 간 원활한 전환
  • 향후 Spring Boot 백엔드로 마이그레이션 예정

4. 성능 최적화

키보드 무한 리렌더링 해결

  • 문제: 키 입력이후 무한정 발생하는 키보드 컴포넌트의 성능 저하
  • 해결: useCallback, useMemo, React.memo를 전략적으로 적용
  • 결과: 모든 폼과 검색창에서 부드러운 타이핑 경험
  • 예시: 최적화된 이벤트 핸들러를 적용한 SearchBar.tsx

5. Monorepo 통합 E2E 테스트

Playwright를 활용한 Frontend + BFF + Backend(Strapi) 통합 테스트

  • 범위: React(Frontend) + NestJS(BFF) + Strapi(Backend 대용) 통합 테스트
  • Monorepo 구조: TurboRepo로 세 애플리케이션을 단일 저장소에서 관리
  • 설정: webServer 설정을 통한 자동 서버 시작/종료
  • 커버리지 (50+ 테스트 파일):
    • 인증 플로우 (로그인, 회원가입, OAuth)
    • 결제 통합 (PortOne 엔드투엔드)
    • 게임 플레이 및 랭킹 모달
    • 사용자 검색 및 팔로우 기능
    • 지갑 및 거래 내역
    • 마이페이지 대시보드 및 필터
  • 실행: pnpm test:e2e (세 애플리케이션 동시 실행)

기술 스택

개발 언어 및 도구

카테고리 기술 버전
언어 TypeScript (100% 타입 안전 코드베이스) 5.x
데이터베이스 MySQL, Redis, SQLite (Strapi 개발용) -
Backend (대용) 현재: Strapi v5 (Headless CMS) - 백엔드 대용
향후: Spring Boot 마이그레이션
5.x / 미정
BFF NestJS, GraphQL (Code-First), TypeORM, TypeScript 10.x
프론트엔드 React 19, Vite, Apollo Client, Panda CSS, Ark UI, Zustand 19 / 5.x
Monorepo TurboRepo, pnpm workspaces latest
테스트 E2E: Playwright (통합)
통합: Jest + Supertest
단위: Jest
1.x / 29.x
인증 JWT, OAuth 2.0 (Google, Kakao) -
결제 PortOne (구 Iamport) -
통신 Client ↔ BFF: GraphQL
BFF ↔ Backend: REST API
-
기타 framer-motion, react-markdown, highlight.js -

📊 기능 요구사항

1. 회원/인증 기능

1.1 인증 기능 (AF)

No. 요구사항명 요구사항 상세 우선순위
AF01 회원가입 사용자 정보 등록 Required
AF02 ID/PW 로그인 ID와 비밀번호를 이용한 로그인 Required
AF03 Google reCaptcha v3 인증 플로우 봇 방지 Required
AF04 ID 찾기 요청 SMTP를 통한 ID 찾기 Required
AF05 ID 찾기 인증 SMTP로 받은 코드 인증 Required
AF06 Google 로그인 Google OAuth 로그인 Required
AF07 Kakao 로그인 Kakao OAuth 로그인 Optional
AF08 Access Token 갱신 만료된 액세스 토큰 갱신 Optional
AF09 비밀번호 재설정 요청 이메일을 통한 비밀번호 재설정 Optional
AF10 비밀번호 재설정 인증 비밀번호 재설정 인증 Optional

1.2 회원 관리 기능 (MF)

No. 요구사항명 요구사항 상세 우선순위
MF01 개인 프로필 조회 본인 프로필 정보 조회 Required
MF02 개인 정보 수정 사용자 정보 수정 Required
MF03 계정 삭제 사용자 계정 삭제 (삭제 대신 비활성화) Required

2. 상품/결제 기능

2.1 상품 기능 (SF)

No. 요구사항명 요구사항 상세 우선순위
SF01 상품 목록 조회 상점의 모든 상품 조회 Required
SF02 상품 상세 정보 조회 특정 상품의 상세 정보 조회 Required

2.2 결제 관리 (PF)

No. 요구사항명 요구사항 상세 우선순위
PF01 결제 준비 PortOne API를 사용한 결제 준비 Required
PF02 결제 검증 및 화폐 지급 결제 검증 및 게임 내 화폐 지급 Required
PF03 PortOne Webhook 수신 PortOne으로부터 재검증 webhook 수신 Required
PF04 구매 내역 조회 사용자 본인의 구매 내역 조회 Required
PF05 구매 상세 정보 조회 상세 구매 정보 조회 Required
PF06 환불 요청 구매한 화폐에 대한 환불 요청 Required
PF07 환불 내역 조회 사용자의 환불 내역 조회 Required
PF08 환불 가능 여부 확인 구매가 환불 가능한지 확인 Required
PF09 결제 실패 알림 결제 실패 시 사용자에게 알림 Required

2.3 지갑 관리 (WF)

No. 요구사항명 요구사항 상세 우선순위
WF01 지갑 잔액 조회 사용자의 현재 화폐 잔액 조회 Required
WF02 거래 내역 조회 화폐 획득/사용 내역 조회 Required
WF03 거래 검색 및 필터 카테고리별 필터링 (결제/언어, 구매/환불), 날짜 Optional

3. 게임/랭킹 기능 (GF)

No. 요구사항명 요구사항 상세 우선순위
GF01 게임 결과 저장 게임 플레이 결과를 서버에 저장 Required
GF02 게임 랭킹 조회 특정 게임의 랭킹 조회 Required
GF03 개인 순위 조회 사용자 본인의 랭킹 위치 조회 Required
GF04 개인 게임 통계 조회 사용자 본인의 게임 통계 조회 Required
GF05 타 사용자 게임 통계 조회 특정 사용자의 게임 정보 조회 Required

핵심 기능:

  • 게임 결과 저장 및 랭킹 업데이트
  • Redis를 활용한 실시간 랭킹 시스템
  • GraphQL Subscription을 통한 실시간 랭킹 업데이트
  • 개인 랭킹 위치 조회
  • 전체 리더보드 조회
  • 특정 사용자 랭킹 및 게임 통계 조회

4. 팔로우/팔로잉 기능 (FF)

No. 요구사항명 요구사항 상세 우선순위
FF01 팔로잉 목록 조회 사용자의 팔로잉 정보 조회 Required
FF02 팔로워 목록 조회 사용자의 팔로워 정보 조회 Required
FF03 사용자 검색 이름으로 사용자 검색 Required
FF04 사용자 팔로우 다른 사용자를 팔로잉 목록에 추가 Required
FF05 사용자 언팔로우 팔로잉 목록에서 사용자 제거 Required

🏗 시스템 아키텍처

GraphQL + REST 하이브리드 아키텍처

┌───────────────────────────────────────────────────────────────┐
│                   Frontend (React 19)                          │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Apollo Client (GraphQL)                               │   │
│  │  - Queries/Mutations                                   │   │
│  │  - Subscriptions (Real-time Ranking)                  │   │
│  │  - Normalized Cache                                    │   │
│  │  - Optimistic UI                                       │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Zustand (Local State)                                 │   │
│  │  - UI State, Game State                                │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Panda CSS + Ark UI                                    │   │
│  └──────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
                         ↓ GraphQL over HTTP
                      POST /graphql
┌───────────────────────────────────────────────────────────────┐
│              BFF (NestJS + GraphQL + TypeORM)                 │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Apollo Server (GraphQL)                               │   │
│  │  - Resolvers (Query, Mutation, Subscription)          │   │
│  │  - Schema-first or Code-first                         │   │
│  │  - DataLoader (Solve N+1 Problem)                     │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Services Layer                                        │   │
│  │  - Data Aggregation (Multiple Backend API calls)      │   │
│  │  - Business Logic                                      │   │
│  │  - Authentication/Authorization                        │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Backend API Client (axios)                            │   │
│  │  - RESTful calls to Strapi/Spring Boot                │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Redis Client                                          │   │
│  │  - Real-time ranking query/update                     │   │
│  │  - PubSub for GraphQL Subscriptions                   │   │
│  └──────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
                         ↓ REST API (JSON)
                 GET/POST/PATCH/DELETE /api/*
┌───────────────────────────────────────────────────────────────┐
│              Backend Server (Strapi v5 / Spring Boot)         │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  REST Controllers                                      │   │
│  │  - User, Payment, Game, Product APIs                  │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Business Logic Layer                                  │   │
│  │  - Service Layer                                       │   │
│  │  - Transaction Management                              │   │
│  └──────────────────────────────────────────────────────────┘ │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │  Data Access Layer                                     │   │
│  │  - ORM (TypeORM/JPA)                                   │   │
│  │  - Database Operations                                 │   │
│  └──────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
                         ↓
┌───────────────────────────────────────────────────────────────┐
│                    Data Layer                                  │
│  ┌────────────────────┐        ┌────────────────────┐         │
│  │   MySQL Database   │        │   Redis Cache      │         │
│  │  (User, Game,      │        │  (Ranking, Session)│         │
│  │   Payment Data)    │        │                    │         │
│  └────────────────────┘        └────────────────────┘         │
└───────────────────────────────────────────────────────────────┘

프로젝트 구조

clonenova/
├── apps/
│   ├── web/                    # React Frontend (GraphQL Client)
│   │   ├── src/
│   │   │   ├── app/           # Routing, Providers
│   │   │   │   └── apollo-provider.tsx
│   │   │   ├── features/      # Feature Modules
│   │   │   │   ├── auth/
│   │   │   │   │   ├── graphql/
│   │   │   │   │   │   ├── queries.ts
│   │   │   │   │   │   └── mutations.ts
│   │   │   │   │   ├── components/
│   │   │   │   │   └── hooks/
│   │   │   │   ├── user/
│   │   │   │   ├── payment/
│   │   │   │   ├── game/
│   │   │   │   ├── ranking/
│   │   │   │   └── follow/
│   │   │   ├── shared/        # Shared Components
│   │   │   ├── stores/        # Zustand Stores
│   │   │   └── lib/           # Utilities
│   │   │       ├── apollo-client.ts
│   │   │       └── portone.ts
│   │   ├── tests/e2e/         # Playwright E2E Tests
│   │   ├── panda.config.ts
│   │   ├── playwright.config.ts
│   │   └── vite.config.ts
│   │
│   ├── bff/                    # NestJS BFF (GraphQL Server)
│   │   ├── src/
│   │   │   ├── schema.gql     # GraphQL Schema (Auto-generated)
│   │   │   ├── app.module.ts
│   │   │   ├── auth/          # Auth Module
│   │   │   ├── users/         # User Module
│   │   │   │   ├── users.resolver.ts
│   │   │   │   ├── users.service.ts
│   │   │   │   └── models/
│   │   │   │       └── user.model.ts
│   │   │   ├── products/      # Product Module
│   │   │   ├── payments/      # Payment Module
│   │   │   │   ├── payments.resolver.ts
│   │   │   │   ├── payments.service.ts
│   │   │   │   └── portone.service.ts
│   │   │   ├── wallets/       # Wallet Module
│   │   │   ├── games/         # Game Module
│   │   │   ├── rankings/      # Ranking Module
│   │   │   │   ├── rankings.resolver.ts
│   │   │   │   └── rankings.service.ts
│   │   │   ├── follows/       # Follow Module
│   │   │   │   ├── follows.resolver.ts
│   │   │   │   └── follows.service.ts
│   │   │   ├── common/        # Common Modules
│   │   │   │   ├── backend-api.service.ts
│   │   │   │   └── redis.service.ts
│   │   │   └── main.ts
│   │   ├── test/integration/  # Integration Tests (Jest + Supertest)
│   │   └── nest-cli.json
│   │
│   └── strapi/                 # Strapi Headless CMS
│       ├── src/
│       │   ├── api/           # Content Types
│       │   │   ├── user/
│       │   │   ├── product/
│       │   │   ├── payment/
│       │   │   └── game/
│       │   └── index.ts
│       ├── data/mock/         # Mock Data Loaders
│       └── config/
│
├── backend/                    # Spring Boot Backend (Future)
│   ├── src/main/java/com/clonenova/
│   │   ├── users/
│   │   ├── products/
│   │   ├── payments/
│   │   ├── wallets/
│   │   ├── games/
│   │   └── follows/
│   └── pom.xml
│
├── packages/
│   ├── shared-types/          # Shared TypeScript Types
│   │   ├── src/
│   │   │   ├── graphql/      # GraphQL Types
│   │   │   ├── rest/         # REST API Types
│   │   │   └── index.ts
│   │   └── package.json
│   ├── ui-components/         # Shared UI Components
│   └── utils/                 # Shared Utilities
│
├── .husky/                    # Git Hooks
│   ├── pre-commit            # ESLint + lint-staged
│   └── pre-push              # TypeCheck + Tests
│
├── turbo.json
├── pnpm-workspace.yaml
└── package.json

🧑🏻‍💻 팀 멤버

이름 역할 GitHub
민영재 Frontend @yeomin4242

📄 라이선스

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published