Communitygithub.com

mehmetmuejde/agent-skills

React/TypeScript 프론트엔드의 모든 작업(컴포넌트, 훅, 상태, 라우팅, 데이터 페칭, 폼, 스타일링, 접근성, i18n, 테스트, 스토리, 성능, 보안)과 새 프로젝트 설정, 도커 이미지 생성, 코드 리뷰에 적용합니다. Vite SPA, React Router 프레임워크 모드(로더, 액션, SSR/하이드레이션), TanStack Query, TanStack Router/React Router, Zustand, React Hook Form/TanStack Form + Zod, Feature-Sliced Design, Biome, 엄격한 TypeScript, Vitest + Testing Library, Playwright, Storybook을 지원합니다. 항상 적용되는 규칙(이펙트 대신 파생 상태, TanStack Query에만 서버 데이터, 내장된 접근성, 모든 기능에 테스트와 스토리 포함, 브라우저 저장소에 토큰 금지)을 포함하며, 주제별 참조를 안내합니다.

agent-skills란 무엇인가요?

이 스킬은 React/TypeScript 프론트엔드 개발을 위한 포괄적인 에이전트 가이드입니다. 개발자가 React 애플리케이션을 구축할 때 항상 지켜야 할 핵심 규칙(파생 상태 사용, 서버 데이터를 TanStack Query로만 관리, 접근성 내장, 모든 기능에 테스트와 스토리 포함, 브라우저 저장소에 민감 정보 저장 금지)을 제공하며, 각 주제에 대한 상세 참조 문서로 연결합니다. Vite SPA, React Router 프레임워크 모드(SSR), TanStack Query, Zustand, React Hook Form/TanStack Form, Feature-Sliced Design, Biome, 엄격한 TypeScript, Vitest, Playwright, Storybook 등 현대적인 React 생태계 스택을 지원합니다. 이 가이드는 Vercel 엔지니어링의 React 모범 사례, OWASP Secure Agent Playbook, Feature-Sliced Design 공식 문서에서 종합되었으며, WCAG 2.2 접근성 기준을 목표로 합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mehmetmuejde/agent-skills/tree/HEAD/skills/react-frontend

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

React 프론트엔드

모든 React 프론트엔드를 위한 규칙입니다. 이 파일은 항상 적용되는 내용을 담고 있습니다. 해당 주제를 작업하기 전에 일치하는 참조 문서를 읽으십시오.

작업읽을 문서
폴더, 레이어, 슬라이스, public API, 임포트, 배럴 파일references/structure.md
FSD 심화: 결정 트리, 교차 임포트, 엔티티, 에셋, 인증/API 배치, 프레임워크 연동, 마이그레이션references/fsd/ (structure.md 끝에 색인)
네이밍, 파일 크기, props, 디자인 시스템, 레이아웃, 상수references/code-style.md
컴포넌트, 훅, 이펙트, 메모이제이션, 트랜지션, 긴 리스트, 하이드레이션references/hooks-and-rendering.md
워터폴, 번들 크기, 코드 스플리팅, 프리로딩, 리렌더링 비용references/performance.md
서버 데이터, 쿼리, 뮤테이션, 로더, 검색 파라미터, Zustandreferences/data-and-state.md
폼, 유효성 검사, 폼 오류references/forms.md
시맨틱, 키보드, 포커스, 대비, 라이브 리전, 접근성 테스트references/accessibility.md (React 구현) + frontend-accessibility 스킬 (전체 규칙, 감사)
단위, 컴포넌트 및 E2E 테스트, 커버리지, API 모킹references/testing.md
스토리, Storybook 접근성 검사, 시각적 회귀references/storybook.md
XSS, HTML/Markdown/LLM 출력 렌더링, 인증, CSRF, CSP, 환경 변수, 로그아웃references/security.md
Node 버전, 패키지 매니저, pre-commit + gitleaks, 의존성 감사references/tooling.md
번역, 언어 전환, <html lang>references/i18n.md
새 프로젝트 설정references/setup.md
프론트엔드 컨테이너 이미지references/docker.md + docker-kubernetes 스킬

스택

  • React 19 (이벤트 이펙트와 <Activity>를 위해 ≥ 19.2) · TypeScript strict
  • 렌더링: Vite SPA 또는 React Router 프레임워크 모드 (SSR + 하이드레이션). React Router 프레임워크 전용으로 표시된 규칙은 해당 모드에만 적용됩니다. Next.js, React Server Components, SWR은 사용하지 않습니다.
  • 라우팅: TanStack Router 또는 React Router — 프로젝트별로 고정, 코드에서 감지하여 혼용하지 않습니다.
  • 서버 상태: TanStack Query · 클라이언트 상태: Zustand
  • 폼: React Hook Form + Zod 또는 TanStack Form + Zod — 프로젝트별로 고정
  • 유효성 검사: 모든 경계(API 응답, 폼, 검색 파라미터, 환경 변수, 스토리지, postMessage)에서 Zod 사용
  • 도구: Biome (린트 + 포맷), Steiger (FSD 규칙), Vitest + Testing Library, Playwright, Storybook
  • React Compiler 없음 → 메모이제이션은 수동으로, 단 측정 후에만 적용합니다.

구조 — Feature-Sliced Design

레이어는 app → pages → widgets → features → entities → shared 순서로 구성됩니다. 임포트는 항상 아래 방향으로만 가능하며, 같은 레이어의 슬라이스 간 임포트는 금지됩니다. 모든 슬라이스는 명시적인 named exports (export * 금지)가 있는 index.ts를 통해서만 임포트됩니다. shared/ui와 shared/lib는 컴포넌트/라이브러리당 하나의 index 파일을 가집니다. app, pages, shared로 시작하며, 빈 레이어 폴더는 만들지 않습니다. 코드는 추출 규칙이 충족될 때까지 페이지에 남아 있습니다. 즉, 현재 여러 곳에서 사용되고, 단일 소비자와 무관하게 변경할 이유가 있으며, 집중된 책임을 가질 때 추출합니다. 세 조건이 모두 충족되지 않으면 중복을 허용합니다. widgets는 권장되지 않습니다: 여러 페이지에서 재사용되는 복합 블록으로 페이지에 포함될 수 없는 경우에만 사용합니다(기존 widgets은 유효함). 자세한 내용: references/structure.md, 상위 규칙서 references/fsd/rules.md.

  • 파일당 하나의 컴포넌트, 파일당 하나의 훅, 컴포넌트당 약 150줄; 컴포넌트 이름에는 슬라이스 이름을 접두사로 붙입니다 (references/code-style.md).
  • 디자인 시스템 우선: shared/ui/의 자체 컴포넌트를 사용합니다. shared/ui/ 외부에서는 shared/ui/primitives/ (UI 라이브러리 CLI 출력물, 직접 수정 금지)를 임포트하지 않습니다. 디자인 시스템 컴포넌트, props, 토큰이 할 수 있는 것을 확인하기 전에 새로운 CSS를 추가하지 않습니다.

컴포넌트와 훅 — 항상

  • 컴포넌트를 다른 컴포넌트 내부에 정의하지 마십시오 — 매 렌더링마다 리마운트됩니다.
  • 파생, 동기화 금지: props나 state로부터 계산할 수 있는 값은 렌더링 중에 계산합니다. props나 state를 state에 복사하는 useEffect를 사용하지 마십시오. key로 리셋합니다.
  • 사용자 액션은 이벤트 핸들러에서 실행되며, state 플래그로 트리거된 이펙트에서 실행되지 않습니다.
  • 이펙트는 외부 시스템과 동기화할 때만 사용하며, 좁은 원시 의존성, 이펙트당 하나의 책임, 정리(cleanup) 함수를 포함합니다. exhaustive-deps 규칙을 절대 무음 처리하지 마십시오.
  • setState(prev => …)는 다음 값이 이전 값에 의존할 때 사용합니다. useState(() => expensive())는 초기 값이 비쌀 때 사용합니다.
  • props나 state를 절대 변이(mutate)하지 마십시오: toSorted(), toReversed(), toSpliced(), with(), spread 연산자를 사용합니다.
  • {count > 0 ? <X /> : null} — 숫자가 왼쪽에 있는 &&는 절대 사용하지 마십시오.
  • useEffect에서 fetch를 사용하지 마십시오. 서버 데이터는 TanStack Query 또는 라우트 로더를 통해 가져옵니다.
  • memo/useMemo/useCallback은 프로파일링 후 또는 참조 안정성이 필요한 경우에만 사용합니다.
  • 오류는 절대 무시하지 않습니다: 빈 catch 블록, .catch(() => {}) 사용 금지. 모든 라우트에는 오류 경계(error boundary)가 있어야 합니다. 모든 쿼리에는 로딩, 오류 및 빈 UI가 있어야 합니다.

데이터와 상태 — 항상

  • 요청 함수 → 훅 → 컴포넌트 순서를 따릅니다. HTTP는 shared/api/의 클라이언트를 통해서만 사용합니다. 훅이나 컴포넌트에서 HTTP 클라이언트를 직접 임포트하지 마십시오.
  • 서버 데이터는 TanStack Query에만 존재하며, queryOptions를 사용한 쿼리 키 팩토리를 통해 관리됩니다. 응답은 요청 함수에서 Zod로 파싱됩니다.
  • 일반 리소스 접근, CRUD 및 쿼리 키 팩토리는 shared/api (또는 해당 페이지만 사용하는 경우 해당 페이지/기능)에 있습니다. entities/<x>/api는 도메인 규칙이나 해당 엔티티의 매핑이 필요한 요청에만 사용합니다.
  • 뮤테이션은 영향을 받는 모든 쿼리를 무효화(업데이트)합니다.
  • URL 상태 (필터, 정렬, 페이지네이션, 탭)는 타입이 지정되고 Zod로 유효성 검사된 검색 파라미터에 저장됩니다. window.location에서 직접 파싱하지 마십시오.
  • Zustand는 공유 클라이언트 상태에만 사용합니다. 항상 selector와 함께 사용합니다. persisted store는 version, migrate 및 partialize를 사용하며, 민감한 데이터를 보관하지 않습니다.
  • 라우트 데이터는 라우트 로더에서 병렬로 로드합니다(queryClient.query({ ...options, staleTime: 'static' }), 이전에는 ensureQueryData라고 불렸습니다). 중첩된 컴포넌트에서 순차적으로 로드하지 마십시오.

접근성 — 내장, 절대 나중에 추가하지 않음

목표: WCAG 2.2 AA. 모든 컴포넌트와 페이지의 완료 정의(definition of done)의 일부입니다. frontend-accessibility 스킬은 완전한 규칙과 감사 절차를 포함합니다. 모든 UI 변경 시 로드하십시오.

  • 시맨틱 HTML 우선: 액션에는 <button>, 탐색에는 <a>/<Link>, 모든 필드에는 <label>, 랜드마크, 하나의 <h1> 및 순서가 있는 제목(headings)을 사용합니다. ARIA는 기본 네이티브 요소가 적합하지 않은 경우에만 사용합니다.
  • 키보드: 모든 요소가 키보드로 접근 및 조작 가능해야 합니다. 양수 tabIndex 사용 금지. 키보드 트랩 금지.
  • 모든 상호작용 요소에 가시적 포커스 (:focus-visible, ≥ 3:1 대비).
  • 포커스 관리: 라우트 변경 시 페이지 제목을 설정하고 포커스를 <h1> 또는 <main>으로 이동합니다. 다이얼로그는 포커스를 트랩하고, Escape 키로 닫히며, 포커스를 트리거로 되돌립니다.
  • 이름(name): 아이콘 버튼은 aria-label을 가집니다. 이미지는 alt 속성을 가집니다 (장식용인 경우 alt="").
  • 텍스트 대비 4.5:1, UI 컴포넌트는 3:1. 색상만으로 정보를 전달하지 않습니다.
  • 움직임 감소(reduced motion)를 존중합니다. 비동기 결과 및 오류에 대해 라이브 리전(role="status"/role="alert")을 사용합니다.
  • 테스트는 역할(role)과 접근 가능한 이름(accessible name)으로 질의합니다. 스토리는 접근성 애드온을 통과합니다. 주요 페이지는 Playwright에서 axe를 통과합니다.

테스트 — 기능과 함께 작성, 나중에 작성하지 않음

  • Vitest + Testing Library 단위 및 컴포넌트 테스트는 모든 기능에 대해 동일한 변경 사항 내에서 작성합니다. UI를 통해 동작을 테스트합니다 (역할, 레이블, user-event). 구현 세부 사항을 테스트하지 않습니다.
  • 라인 커버리지 ≥ 80%, 브랜치 커버리지 ≥ 80%, CI에서 Vitest 임계값으로 적용됩니다.
  • Playwright E2E는 모든 중요 사용자 흐름(로그인, 핵심 비즈니스 흐름, 결제/체크아웃, 권한)에 대해 작성합니다. 역할 기반 로케이터 사용, 고정 대기 금지, 재사용된 인증 상태, 주요 페이지의 axe 스캔.
  • 모든 공유/재사용 UI 컴포넌트에 대한 Storybook 스토리, 모든 상태(기본, 로딩, 빈, 오류, 비활성화, 긴 내용)를 다룹니다. 기본적으로 데스크톱 뷰포트를 사용하며, 프로젝트에서 반응형 레이아웃이 필요한 경우에만 모바일 뷰포트를 추가합니다.
  • Storybook + Playwright 스크린샷을 통한 시각적 회귀 테스트. 스냅샷 테스트는 드물게 그리고 목표를 정해서만 사용합니다.

보안 — 항상

  • dangerouslySetInnerHTML 금지 (DOMPurify 사용 시 예외). React 외부에서는 textContent를 사용하고 innerHTML을 절대 사용하지 않습니다. 모델 출력 및 Markdown을 원시 HTML로 렌더링하지 않습니다.
  • localStorage/sessionStorage/IndexedDB에 토큰이나 민감 데이터를 저장하지 않습니다. 인증은 백엔드에서 설정한 HttpOnly 세션 쿠키를 사용합니다. OIDC의 경우 backend-for-frontend 패턴을 선호합니다.
  • 상태를 변경하는 요청은 CSRF 헤더를 보냅니다. credentials: 'include'는 자체 API에만 사용합니다.
  • VITE_* 변수는 공개입니다 — 절대 비밀 정보를 포함하지 마십시오.
  • ?redirect= 대상은 동일 출처(same-origin) 상대 경로만 허용합니다 (오픈 리다이렉트 방지).
  • 로그아웃 시 서버 세션, TanStack Query 캐시 및 모든 persisted store를 지웁니다.
  • CSP는 HTTP 헤더로 설정하며 object-src 'none', base-uri 'none', frame-ancestors를 포함합니다.
  • postMessage 핸들러는 event.origin을 확인합니다. 신뢰할 수 없는 객체를 병합하지 마십시오 (프로토타입 오염).
  • 프론트엔드는 절대 권한 부여를 강제하지 않습니다. 백엔드가 담당합니다 [ASVS 8.3.1].

TypeScript 및 Biome

  • strict 활성화 (TypeScript 7부터 기본값 — 명시적으로 유지). noUncheckedIndexedAccess, verbatimModuleSyntax, moduleResolution: "bundler", lib는 ES2023 + DOM을 포함합니다. TypeScript 7에서는 types 기본값이 []이므로 "vite/client"를 명시적으로 나열하십시오. baseUrl은 사라졌으므로 paths를 사용합니다 ("@/*": ["./src/*"]).
  • any 금지 (unknown을 사용하고 좁혀서 사용), 오류를 무음 처리하기 위한 non-null 단언 금지, @ts-ignore 금지 (불가피한 경우 @ts-expect-error를 이유와 함께 사용). 매직 넘버나 문자열 금지 — shared/config/ 또는 해당 슬라이스의 config/model에 명명된 상수로 정의합니다.
  • 외부 데이터의 타입은 Zod 스키마(z.infer/z.output)에서 가져오며, 수동으로 작성하여 불일치가 발생할 수 있는 인터페이스를 사용하지 않습니다.
  • Biome: 권장 규칙에 noNestedComponentDefinitions, noReExportAll 및 noConsole 추가 (권장 세트에 포함되지 않음). noBarrelFile은 슬라이스 index.ts 파일에 대해 비활성화합니다 (references/structure.md).
  • biome ci, tsc --noEmit, steiger ./src 및 knip이 로컬 및 CI를 통과해야 합니다. 이유를 설명하는 주석 없이 인라인 규칙을 비활성화하지 마십시오.
  • 주석은 영어로 작성합니다. TODO는 프로젝트의 TODO 마커를 사용합니다.

저장소 위생 — 항상

  • Node 버전 고정: .nvmrc (LTS), package.json의 engines와 engine-strict, 정확한 npm/pnpm 버전의 packageManager. lockfile은 커밋됩니다.
  • pre-commit을 commit 및 push에 대해 설치합니다: staged 변경 사항과 모든 푸시되지 않은 커밋에 대한 gitleaks, Biome. push 시 tsc, 관련 Vitest 테스트 및 의존성 감사. --no-verify로 절대 우회하지 마십시오.
  • CI에서 모든 MR 및 정기적인 일정에 따라 의존성 감사를 실행합니다.

자세한 내용: references/tooling.md.

Docker 및 배포

컨테이너 이미지, .dockerignore, Compose 및 Kubernetes는 docker-kubernetes 스킬에서 다룹니다. 프론트엔드 워크플로 및 체크리스트는 references/docker.md에 있습니다. 모든 이미지에는 .dockerignore가 있습니다. 해당 스킬에서 존중해야 할 프론트엔드 특화 사항:

  • VITE_* 값은 빌드 시 번들에 포함됩니다. 여러 환경을 위한 단일 이미지에는 런타임 구성이 필요합니다: 컨테이너 시작 시 환경 변수에서 작성되어 앱 시작 시 가져와 유효성 검사되는 config.json(또는 config.js)을 제공합니다. 여전히 공개 정보이며 비밀 정보를 포함하지 않습니다.
  • Vite SPA는 정적 파일입니다: 클라이언트 측 라우트를 위해 index.html로 폴백하는 웹 서버에서 제공하며, 해시된 에셋은 장기 캐시, index.html은 no-cache, references/security.md의 보안 헤더를 적용합니다.
  • React Router 프레임워크 모드 (SSR) 는 런타임에 Node 서버가 필요합니다 (react-router-serve 또는 사용자 정의 서버). 정적 배포가 아닙니다.

작성 후

결과에 대한 보안 검토를 위해 appsec-review 스킬을 제안하십시오.

출처

Vercel Engineering의 React 모범 사례(github.com/vercel-labs/agent-skills, react-best-practices, MIT 라이선스) — Next.js에서 Vite/React Router + TanStack Query로 적용; 추적성을 위해 규칙 ID 유지 — 및 OWASP Secure Agent Playbook (CC BY 4.0; OWASP ASVS 5.0)의 내용을 결합했습니다. 구조는 Feature-Sliced Design (feature-sliced.design, fsd.how)을 따릅니다. references/fsd/는 공식 FSD 에이전트 스킬 (github.com/feature-sliced/skills, MIT 라이선스)에서 적용되었습니다. 접근성 목표: WCAG 2.2.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬