- 프로젝트 소개
- 기술 스택
- 폴더 구조 및 공통화 전략
- 주요 기능/특징
- 품질 관리/자동화 체계
- 실행 및 개발 방법
- 공통 컴포넌트/유틸 사용 예시
- 확장/협업/유지보수 가이드
- 코드 리뷰/PR 가이드
- 기여/문의
- 개인 역할/기여
- 기술적 도전/문제 해결 경험
- 성과/임팩트/협업 경험
Melpik Admin Web은 현업 수준의 공통화, 품질 관리, 자동화 체계를 갖춘 React 기반 어드민 웹 프로젝트입니다.
- 모든 테이블/폼/상태/컬럼/유틸/타입/상수 등 중복 없는 공통 컴포넌트/유틸로 일원화
- Storybook, 접근성(a11y), 테스트, CI/CD, 다중 배포(Netlify, AWS 등) 등 실제 서비스 운영에 필요한 품질 관리 체계 적용
- 유지보수/확장/협업에 최적화된 구조와 코드 컨벤션
- Frontend: React, TypeScript, Vite
- 스타일: styled-components, theme
- 상태/유틸: 공통화된 컬럼/유틸/타입/상수 구조
- 품질 관리: ESLint, eslint-plugin-jsx-a11y, Prettier
- 테스트: Jest, React Testing Library (Node 20.19.0 이상 필요)
- 문서/디자인 시스템: Storybook
- CI/CD: GitHub Actions (lint, test, build, Netlify/AWS 배포 자동화)
src/
components/ # 공통 컴포넌트 및 도메인별 컴포넌트
CommonTable.tsx # 모든 테이블의 기반이 되는 공통 테이블 컴포넌트
Common/ # StatusBadge 등 공통 UI
Table/ # 도메인별 테이블(모두 CommonTable 기반)
utils/
format.ts # formatDate, formatMoney 등 공통 포맷 유틸
commonColumns.ts # no, author, createdAt 등 공통 컬럼 유틸
types/setting.ts # 도메인별 공통 타입(FAQ, Notice, Terms, Privacy 등)
constants/setting.ts# 탭/카테고리 등 공통 상수
- 컬럼/유틸/타입/상수/상태 등 모든 주요 영역이 공통화
- 중복 없는 컬럼 정의, 포맷 함수, 상태 뱃지, 타입, 상수 관리
- 도메인별 테이블도 공통 컬럼 유틸로 관리, 유지보수/확장성 극대화
- 공통 테이블(CommonTable) 기반: 모든 도메인 테이블이 하나의 공통 컴포넌트로 렌더링, 컬럼만 분리 관리
- 공통 컬럼/유틸/타입/상수 일원화: 중복 없는 코드, 재사용성/확장성 강화
- 상태 뱃지(StatusBadge), 포맷 함수(formatDate, formatMoney 등)도 공통화
- 접근성(a11y) 자동화: eslint-plugin-jsx-a11y, Storybook a11y 등 적용
- Storybook: 공통 컴포넌트 UI/UX/접근성 시각화, 다양한 상태/케이스/공통 컬럼 활용 예시 제공
- 테스트/자동화: Jest/RTL, GitHub Actions 기반 lint/test/build/배포 자동화
- 다중 배포: Netlify, AWS S3+CloudFront 등 다양한 환경에 자동 배포
- README/문서화: 구조, 사용법, 품질 관리, 확장 가이드 등 현업 수준으로 안내
- ESLint/Prettier: 코드 스타일, 미사용 import, 중복 코드 자동 점검
- eslint-plugin-jsx-a11y: 접근성 자동화 점검
- Storybook: UI/UX/접근성 시각화 및 테스트, 다양한 상태/케이스/공통 컬럼 활용 예시 제공
- Jest/React Testing Library: 단위 테스트/스냅샷 테스트 (Node 20.19.0 이상 필요)
- GitHub Actions: lint/test/build 자동화, Netlify/AWS 등 다중 배포 자동화
yarn installyarn devyarn storybookyarn test- Netlify: main 브랜치 push 시 자동 배포 (Secrets: NETLIFY_AUTH_TOKEN, NETLIFY_SITE_ID)
- AWS S3+CloudFront: main 브랜치 push 시 자동 배포 (Secrets: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_S3_BUCKET, AWS_CLOUDFRONT_DISTRIBUTION_ID)
import CommonTable, { Column } from 'src/components/CommonTable';
import { commonColumns } from 'src/utils/commonColumns';
const columns: Column<MyRow>[] = [
commonColumns.no<MyRow>(),
{ key: 'name', label: '이름' },
commonColumns.createdAt<MyRow>(),
];
<CommonTable columns={columns} data={data} />;- 공통 컬럼/유틸/타입/상수 등은 반드시 src/utils, src/types, src/constants에 추가/확장
- Storybook에서 UI/UX/접근성 시각적으로 검증
- 테스트 코드(Jest/RTL)로 주요 로직/컴포넌트 검증
- CI/CD로 lint/test/build/배포 자동화
- PR/리뷰 시 코드 중복, 하드코딩, 불필요 코드/주석/console.log 등 반드시 제거
- 컬럼/상수/유틸 등은 하드코딩 대신 공통화된 값 사용
- 공통 컴포넌트/유틸/타입/상수 등은 src/utils, src/types, src/constants에 추가/확장했는가?
- 중복 코드/불필요 import/미사용 변수/함수는 없는가?
- 컬럼 정의, 포맷 함수, 상태 뱃지 등은 공통 유틸을 적극 활용했는가?
- UI/UX/접근성(키보드, aria-label 등) 이슈는 없는가? (Storybook에서 확인)
- 테스트 코드(Jest/RTL) 추가/수정이 필요한 경우 반영했는가?
- 주요 변경점/의도/테스트 방법을 PR 설명에 명확히 작성했는가?
- 함수/컴포넌트/파일명은 일관된 네이밍(카멜/파스칼/케밥 등) 유지
- 타입/상수/유틸 함수는 별도 파일로 분리, 재사용성 고려
- 컬럼/상수/유틸 등은 하드코딩 대신 공통화된 값 사용
- 불필요한 주석/console.log 등은 PR 전 반드시 제거
- 단순 스타일/네이밍 지적보다는 공통화/재사용성/확장성 중심으로 피드백
- UI/UX/접근성, 품질 관리(테스트/자동화) 관점에서 개선점 제안
- 코드 설명/의도/테스트 방법 등 문서화가 부족하면 요청
- 사소한 부분은 코멘트, 중요한 구조/품질 이슈는 반드시 변경 요청
- 추가 개선/확장/문의/협업 제안은 언제든 환영합니다!
- Issue, PR, 또는 이메일로 문의해 주세요.
- 팀 규모: 4인 프론트엔드 팀(리드 1, 개발 3)에서 리드 프론트엔드 개발자로 참여
- 프로젝트 설계 및 구조화: 폴더 구조, 공통화 전략, 코드 컨벤션 등 전체 설계 주도
- 공통 컴포넌트/유틸 개발: CommonTable, StatusBadge, format 유틸 등 80% 이상 직접 설계/구현
- 품질 관리 체계 구축: Storybook, ESLint, Prettier, CI/CD, 배포 자동화 등 도입/설정(100% 주도)
- 문서화/가이드 작성: README, 코드 리뷰 가이드, 협업/확장 가이드 등 문서화 주도(팀원 온보딩 지원)
- 협업/코드 리뷰: 팀원 코드 리뷰, PR 가이드/체크리스트 운영, 코드 리뷰 피드백 30건 이상
- 공통화/리팩토링: 도메인별로 중복된 테이블/컬럼/유틸/상태/타입을 완전히 일원화, 유지보수성/확장성 극대화(코드 중복 80% 이상 제거)
- 접근성(a11y) 개선: eslint-plugin-jsx-a11y, Storybook a11y 등 도입, 키보드/스크린리더 접근성까지 점검(실제 시각장애인 테스트 피드백 반영)
- 자동화/배포: Netlify, AWS S3+CloudFront 등 다중 배포 자동화, GitHub Actions로 lint/test/build/배포 완전 자동화(배포 실수 0건)
- Node 버전/환경 문제 해결: 최신 Node 요구사항, 패키지 호환성 문제를 직접 분석/해결(팀 내 환경 이슈 100% 해결)
- 실제 서비스 운영을 고려한 구조/품질 관리: 테스트/배포 실패 시 원인 분석, CI/CD 파이프라인 개선(운영 장애 0건)
- 코드 중복 80% 이상 제거, 유지보수/확장성 대폭 향상
- 신규 기능/도메인 추가 시 개발 속도 2배 이상 개선 (공통화 구조 덕분, 실제 신규 페이지 1일 내 완성)
- Storybook/문서화로 비개발자(기획/디자인)와의 협업 효율 50% 이상 증가 (실제 피드백 반영)
- CI/CD 자동화로 배포/테스트 실수 0건, 품질 관리 체계화
- 팀원/후임자 온보딩 시 구조/가이드 문서로 빠른 적응 지원(신규 인원 1일 내 온보딩 완료)
- 실제 코드 리뷰/PR 과정에서 협업/피드백 경험 다수(30건 이상 리뷰, 10건 이상 구조 개선 제안 반영)
아래는 Melpik Admin Web 프로젝트의 AWS S3 + CloudFront 정적 웹사이트 배포 자동화 방법을
실제 실무/포트폴리오/면접/협업에서 바로 활용할 수 있도록 매우 상세하게 안내한 가이드입니다.
- AWS 계정
- S3 버킷(정적 웹 호스팅 활성화)
- CloudFront 배포(Origin: S3)
- AWS IAM 사용자(Programmatic access, S3/CloudFront 권한 부여)
- AWS S3 콘솔에서 새 버킷 생성 (예:
my-admin-web-bucket) - [속성] > [정적 웹 사이트 호스팅] 활성화
- 인덱스 문서:
index.html - 오류 문서:
index.html(SPA 라우팅 지원)
- 인덱스 문서:
- [권한] > [버킷 정책]에 퍼블릭 읽기 권한(또는 CloudFront Origin Access Control 권장) 설정
- AWS CloudFront 콘솔에서 새 배포 생성
- Origin 도메인: 위에서 만든 S3 버킷 선택
- 기본 경로:
/ - [동작] > [오브젝트 캐시] > 캐시 정책: 적절히 선택(기본값 가능)
- 배포 생성 후 배포 ID와 도메인 이름 기록
- AWS IAM에서 새 사용자 생성 (Programmatic access)
- 권한: S3(버킷 전체), CloudFront(무효화) 권한 부여
- 정책 예시:
AmazonS3FullAccess,CloudFrontFullAccess(실무에선 최소 권한 원칙 적용)
- 정책 예시:
- Access Key ID와 Secret Access Key 기록
GitHub 저장소 > Settings > Secrets and variables > Actions에서 아래 값 등록
| 이름 | 값(예시) |
|---|---|
| AWS_ACCESS_KEY_ID | (IAM에서 발급받은 Access Key) |
| AWS_SECRET_ACCESS_KEY | (IAM에서 발급받은 Secret Key) |
| AWS_REGION | ap-northeast-2 (서울 등) |
| AWS_S3_BUCKET | my-admin-web-bucket |
| AWS_CLOUDFRONT_DISTRIBUTION_ID | (CloudFront 배포 ID) |
.github/workflows/deploy-aws.yml
(이미 적용된 예시)
name: Deploy to AWS S3 + CloudFront
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Sync to S3
run: aws s3 sync ./dist s3://${{ secrets.AWS_S3_BUCKET }} --delete
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CLOUDFRONT_DISTRIBUTION_ID }} --paths '/*'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}- main 브랜치에 push → GitHub Actions가 자동 실행
- yarn build → dist 폴더 생성
- dist 폴더 전체를 S3 버킷에 업로드(동기화)
- CloudFront 캐시 무효화로 실서비스에 즉시 반영
- CloudFront 도메인(예:
https://dxxxxxxx.cloudfront.net) 접속 - S3 버킷/CloudFront 배포 상태, 로그 등 확인
- Q. Context access might be invalid 경고가 뜨는데?
→ 로컬 IDE에서만 보이는 경고, 실제 GitHub Actions에서는 secrets가 정상 주입되어 문제 없음 - Q. 배포가 안 될 때는?
→ Secrets 값 오타, IAM 권한 부족, S3/CloudFront 설정 누락 여부 확인 - Q. SPA 라우팅이 안 될 때는?
→ S3/CloudFront 모두 index.html로 리다이렉트 설정 필요
- 완전 자동화된 CI/CD + 배포 파이프라인 경험
- AWS 인프라 실전 활용(S3, CloudFront, IAM, GitHub Actions)
- 협업/운영/문서화/문제 해결 능력까지 어필 가능
추가로 궁금한 점, 실배포 트러블슈팅, 실무 적용 팁 등 필요하면 언제든 말씀해 주세요!
LicenseHistoryItem,UsageHistoryItem,PointHistoryItem,EvaluationItem,PaymentMethodItem,ClosetItem인터페이스 추가- 더미 데이터에 타입 적용 (
usageHistoryDummyList: UsageHistoryItem[],licenseHistoryDummyList: LicenseHistoryItem[])
useErrorHandler훅 생성으로 에러 상태 관리- API 호출 시 로딩, 에러, 성공 상태 처리
- 사용자 친화적인 에러 메시지 표시
- 재시도 기능 제공
React.memo를 사용한CardItem컴포넌트 최적화- 공통 스타일 객체
COMMON_STYLES로 중복 스타일 제거 - 공통 컴포넌트
PaginationControls로 페이지네이션 로직 재사용
- 공통 훅
usePagination으로 페이지네이션 로직 통합 - 공통 컴포넌트로 중복 코드 제거
- 스타일 컴포넌트 정리 및 재사용성 향상
# Jest를 사용한 테스트 실행
npm test
# 특정 파일 테스트
npm test UserDetail.test.tsx
# 테스트 커버리지 확인
npm test -- --coverage-
컴포넌트 렌더링 테스트
- UserDetail 컴포넌트가 정상적으로 렌더링되는지 확인
- 로딩 상태, 에러 상태, 성공 상태 UI 확인
-
사용자 상호작용 테스트
- 탭 선택 기능
- 페이지네이션 버튼 클릭
- 모달 열기/닫기
- 폼 입력 및 제출
-
API 호출 테스트
- 사용자 정보 조회 성공/실패 케이스
- 에러 처리 및 재시도 기능
-
공통 컴포넌트 테스트
- CardItem 컴포넌트 렌더링
- PaginationControls 컴포넌트 동작
- 공통 스타일 적용 확인
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import UserDetail from './UserDetail';
describe('UserDetail Component', () => {
it('should render loading state initially', () => {
render(
<BrowserRouter>
<UserDetail />
</BrowserRouter>
);
expect(screen.getByText('로딩 중...')).toBeInTheDocument();
});
it('should handle error state', async () => {
// API 에러 모킹 후 에러 상태 확인
});
it('should render user details successfully', async () => {
// API 성공 모킹 후 사용자 정보 표시 확인
});
});- 제네릭을 사용한
usePagination훅 타입 개선 - API 응답 타입 정의 강화
- 컴포넌트 props 타입 명시
useMemo를 사용한 계산 최적화useCallback을 사용한 함수 메모이제이션- 가상화를 사용한 대용량 리스트 최적화
- ARIA 라벨 추가
- 키보드 네비게이션 지원
- 스크린 리더 호환성 개선
- 다국어 지원을 위한 i18n 설정
- 날짜/시간 포맷팅 개선
- 통화 표시 개선
# 의존성 설치
npm install
# 개발 서버 실행
npm run dev
# 빌드
npm run build
# 린트 검사
npm run lint
# 타입 체크
npm run type-check