xiaohongshu
xiaohongshu
frontend-fsd-architect
Feature-Sliced Design architecture specialist
Full skill instructions
Frontend FSD Architect는 Feature-Sliced Design(FSD) v2.1 표준을 기반으로 중대규모 프론트엔드 프로젝트의 아키텍처를 자동 생성, 마이그레이션, 검증하는 전문 Skill입니다.
대규모 프론트엔드 개발에서 가장 큰 문제인 "코드를 어디에 둘지 모호함", "의존성 혼란", **"팀 협업 충돌"**을 FSD의 7계층 구조와 엄격한 의존성 규칙으로 해결합니다.
다음 상황에서 이 Skill을 사용하세요:
7계층 FSD 폴더 구조 + 보일러플레이트 코드 완전 자동화
지원 구조:
src/
├── app/ # 애플리케이션 초기화
├── pages/ # 페이지 단위 조합
├── widgets/ # 독립 UI 블록
├── features/ # 비즈니스 기능
├── entities/ # 도메인 객체
└── shared/ # 공통 라이브러리
생성 항목:
React, Vue, Angular, Svelte 맞춤형 코드 템플릿
// features/auth/login/ui/LoginForm.tsx
import { useState } from 'react';
import { useLoginMutation } from '../api/loginApi';
export const LoginForm = () => {
const [login, { isLoading }] = useLoginMutation();
// ... 컴포넌트 로직
};
<!-- features/auth/login/ui/LoginForm.vue -->
<script setup lang="ts">
import { ref } from 'vue';
import { useLogin } from '../api/loginApi';
const { mutate: login, isPending } = useLogin();
</script>
의존성 위반, 네이밍 불일치 등 10개 규칙 자동 검증
설정 파일 생성:
// steiger.config.ts
import { defineConfig } from 'steiger';
import fsd from '@feature-sliced/steiger-plugin';
export default defineConfig([
...fsd.configs.recommended,
{
files: ['./src/shared/**'],
rules: { 'fsd/no-public-api-sidestep': 'off' }
}
]);
검증 규칙:
fsd/forbidden-imports - 상위 레이어 import 금지fsd/no-cross-slice-dependency - 동일 레이어 간 의존성 금지fsd/no-public-api-sidestep - Public API 우회 금지fsd/inconsistent-naming - 네이밍 일관성fsd/excessive-slicing - 과도한 분할 경고기존 프로젝트를 5단계로 안전하게 전환
Phase 1: Shared 레이어 정의 (1~2주)
기존: /components/Button.tsx, /utils/formatPrice.ts
FSD: /shared/ui/Button, /shared/lib/formatters/formatPrice.ts
Phase 2: Entities 레이어 정의 (2~3주)
기존: /models/User.ts, /services/userService.ts
FSD: /entities/user/model/types.ts, /entities/user/api/userApi.ts
Phase 3: Features 추출 (4~6주)
기존: HomePage.tsx (로그인+검색+장바구니 모두 포함)
FSD: /features/auth/login, /features/product/search, /features/cart/add
Phase 4: Pages/Widgets 재구성 (2~3주)
페이지를 조합 레이어로 재구성
Phase 5: Steiger 적용 + 규칙 강화 (1~2주)
CI/CD 통합, 의존성 위반 수정
산업별(금융/의료/이커머스) 특수 요구사항 반영
금융 도메인 예시:
// entities/account/model/types.ts
export interface BankAccount {
accountNumber: string; // 계좌번호 (암호화)
balance: number; // 잔액 (KRW)
currency: 'KRW' | 'USD'; // 통화
regulatoryCompliance: { // 규제 준수
kycVerified: boolean;
amlCheckDate: Date;
};
}
// shared/lib/validators/validateAccount.ts
export const validateKoreanAccount = (account: string): boolean => {
// 한국 계좌번호 형식 검증: XXX-XXXX-XXXXX
return /^\d{3}-\d{4}-\d{5}$/.test(account);
};
Step 1: 파일 다운로드
이 SKILL.md 파일을 로컬에 저장
Step 2: 프로젝트 설정
1. https://claude.ai 접속
2. Projects → "+ New Project" 클릭
3. 프로젝트 이름: "[Your Project Name]"
4. Settings (⚙️) 아이콘 클릭
Step 3: Skill 업로드
1. Project Knowledge 섹션 이동
2. "Add Content" 클릭
3. 파일 업로드: frontend-fsd-architect-skill.md
4. Save 버튼 클릭
Step 4: 검증
채팅창에서 테스트:
"이커머스 프로젝트의 FSD 구조를 생성해줘. React + TypeScript,
팀 5명, features: 로그인, 장바구니, 결제, 관리자"
예상 결과: 완전한 폴더 구조 + 보일러플레이트 코드 생성
Step 1: 전역 설치 (모든 프로젝트)
# Skill 폴더 생성
mkdir -p ~/.claude/skills
# Skill 파일 복사
cp frontend-fsd-architect-skill.md ~/.claude/skills/
# 권한 설정
chmod 644 ~/.claude/skills/frontend-fsd-architect-skill.md
# 확인
claude skills list
# 출력: frontend-fsd-architect-skill (enabled)
Step 2: 프로젝트별 설치 (선택)
# 프로젝트 루트로 이동
cd /path/to/your-project
# 프로젝트 Skill 폴더 생성
mkdir -p .claude/skills
# Skill 파일 복사
cp ~/Downloads/frontend-fsd-architect-skill.md .claude/skills/
# 확인
claude skills list --local
Step 3: 사용 예시
# CLI에서 직접 사용
claude "내 프로젝트를 FSD 구조로 변환해줘.
기존 구조: MVC (components/, services/),
프레임워크: Vue 3 + Pinia"
# 또는 채팅 모드
claude chat
> FSD 구조로 프로젝트 생성해줘
시나리오: React + TypeScript 이커머스 프로젝트 시작
입력 (Claude에게 요청):
FSD 구조로 이커머스 프로젝트를 생성해줘.
요구사항:
- 프레임워크: React 18 + TypeScript
- 상태관리: Redux Toolkit
- 팀 규모: 5명
- 주요 기능:
1. 사용자 인증 (로그인, 회원가입, 로그아웃)
2. 상품 관리 (목록, 상세, 검색, 필터)
3. 장바구니 (추가, 수정, 삭제)
4. 결제 (주문서, 결제, 완료)
5. 관리자 (상품 등록, 주문 관리)
출력 (자동 생성):
src/
├── app/
│ ├── providers/
│ │ ├── router.tsx # React Router 설정
│ │ ├── store.ts # Redux Store 설정
│ │ └── theme.tsx # Styled-components Theme
│ ├── styles/
│ │ └── global.css
│ └── index.tsx
│
├── pages/
│ ├── home/
│ │ ├── ui/HomePage.tsx
│ │ └── index.ts
│ ├── product-detail/
│ │ ├── ui/ProductDetailPage.tsx
│ │ ├── model/useProductLoader.ts
│ │ └── index.ts
│ ├── cart/
│ ├── checkout/
│ └── admin-dashboard/
│
├── widgets/
│ ├── header/
│ │ ├── ui/Header.tsx
│ │ ├── model/useAuthStatus.ts
│ │ └── index.ts
│ ├── product-grid/
│ └── shopping-cart-preview/
│
├── features/
│ ├── auth/
│ │ ├── login/
│ │ │ ├── ui/LoginForm.tsx
│ │ │ ├── model/loginSlice.ts
│ │ │ ├── api/loginApi.ts
│ │ │ └── index.ts
│ │ ├── signup/
│ │ └── logout/
│ ├── product/
│ │ ├── search/
│ │ ├── filter/
│ │ └── add-to-cart/
│ ├── cart/
│ │ ├── update-quantity/
│ │ └── remove-item/
│ └── payment/
│ ├── create-order/
│ └── process-payment/
│
├── entities/
│ ├── user/
│ │ ├── model/types.ts
│ │ ├── api/userApi.ts
│ │ ├── ui/UserCard.tsx
│ │ └── index.ts
│ ├── product/
│ ├── order/
│ └── cart/
│
└── shared/
├── ui/
│ ├── Button/
│ ├── Input/
│ └── Modal/
├── lib/
│ ├── formatters/formatPrice.ts
│ ├── validators/validateEmail.ts
│ └── utils/debounce.ts
├── api/
│ ├── client.ts
│ └── types.ts
└── config/
└── constants.ts
+ package.json (스크립트 추가)
+ steiger.config.ts (린터 설정)
+ .eslintrc.js (ESLint 통합)
+ tsconfig.json (Path alias 설정)
+ README.md (프로젝트 구조 설명)
추가 생성 파일:
// features/auth/login/ui/LoginForm.tsx (보일러플레이트)
import { useState } from 'react';
import { useAppDispatch } from '@/app/providers/store';
import { loginAsync } from '../model/loginSlice';
import { Button, Input } from '@/shared/ui';
export const LoginForm = () => {
const dispatch = useAppDispatch();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await dispatch(loginAsync({ email, password }));
};
return (
<form onSubmit={handleSubmit}>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="이메일"
/>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="비밀번호"
/>
<Button type="submit">로그인</Button>
</form>
);
};
시나리오: MVC 구조의 Vue 프로젝트를 FSD로 전환
입력:
기존 Vue 프로젝트를 FSD 구조로 마이그레이션해줘.
현재 구조:
src/
├── components/
│ ├── Header.vue
│ ├── ProductList.vue
│ └── LoginForm.vue
├── views/
│ ├── HomePage.vue
│ └── ProductDetailPage.vue
├── services/
│ ├── authService.ts
│ └── productService.ts
├── store/
│ └── index.ts
└── utils/
└── formatters.ts
프로젝트 정보:
- 코드 규모: 약 35,000 LOC
- 팀: 4명
- 주요 문제: components/ 폴더 200개 파일, 의존성 혼란
출력: 5단계 마이그레이션 계획 + 각 단계별 상세 가이드
# Vue 프로젝트 FSD 마이그레이션 계획
## Phase 1: Shared 레이어 정의 (1주)
### 작업 내용
1. 공통 컴포넌트 이동
- components/Button.vue → shared/ui/Button/Button.vue
- components/Input.vue → shared/ui/Input/Input.vue
2. 유틸리티 함수 재구성
- utils/formatters.ts → shared/lib/formatters/
- utils/validators.ts → shared/lib/validators/
### 마이그레이션 스크립트
```bash
# 자동 이동 스크립트 (dry-run)
node scripts/migrate-to-shared.js --dry-run
# 실제 실행
node scripts/migrate-to-shared.js
[상세 가이드...]
---
### Parameters Reference
이 Skill은 자연어 대화로 작동하므로 명령어 매개변수는 없지만, 요청 시 포함하면 좋은 정보:
| 정보 | 설명 | 예시 | 필수 여부 |
|------|------|------|----------|
| **프레임워크** | 사용 중인 프론트엔드 프레임워크 | React, Vue, Angular, Svelte | ✅ 필수 |
| **상태관리** | 상태관리 라이브러리 | Redux, Zustand, Pinia, NgRx | ⚠️ 권장 |
| **팀 규모** | 개발자 수 | 3명, 5명, 10명+ | ⚠️ 권장 |
| **프로젝트 규모** | 예상 코드 라인 수 | 20k LOC, 50k LOC, 100k+ LOC | ⚠️ 권장 |
| **주요 기능** | 비즈니스 기능 목록 | 로그인, 결제, 대시보드... | ✅ 필수 |
| **도메인** | 산업 분야 | 이커머스, 금융, 의료, B2B... | ❌ 선택 |
| **특수 요구사항** | 규제, 보안 등 | HIPAA, PCI-DSS, GDPR... | ❌ 선택 |
| **기존 구조** | 현재 폴더 구조 (마이그레이션 시) | MVC, Atomic Design... | ⚠️ 권장 |
---
## Examples
### Example 1: 소규모 SaaS 대시보드 (React)
**난이도**: ⭐ 기본
**시나리오**: 스타트업의 관리자 대시보드
**요청**:
FSD 구조로 관리자 대시보드를 만들어줘.
**생성 구조**:
src/ ├── app/ ├── pages/ │ ├── dashboard/ # 대시보드 메인 │ ├── users/ # 사용자 목록 │ └── settings/ # 설정 ├── widgets/ │ ├── stats-card/ # 통계 카드 │ ├── user-table/ # 사용자 테이블 │ └── settings-panel/ # 설정 패널 ├── features/ │ ├── user/ │ │ ├── filter/ # 사용자 필터링 │ │ └── export/ # 데이터 내보내기 │ └── settings/ │ └── update-profile/ ├── entities/ │ ├── user/ │ └── stat/ └── shared/ └── ui/ ├── Card/ └── Table/
총 파일: ~25개 | 예상 크기: ~8KB
---
### Example 2: 중규모 이커머스 (Vue)
**난이도**: ⭐⭐ 중급
**시나리오**: 온라인 쇼핑몰
**요청**:
Vue 3 이커머스 프로젝트를 FSD로 구성해줘.
**생성 구조**:
src/ ├── app/ ├── pages/ # 10개 페이지 ├── widgets/ # 15개 위젯 ├── features/ # 20개 features │ ├── product/ │ │ ├── search/ │ │ ├── filter/ │ │ └── add-to-wishlist/ │ ├── cart/ │ │ ├── add-item/ │ │ ├── update-quantity/ │ │ └── apply-coupon/ │ ├── payment/ │ │ ├── select-method/ # 결제 수단 선택 │ │ ├── process-card/ # 카드 결제 │ │ └── process-bank/ # 계좌이체 │ └── admin/ │ ├── manage-product/ │ └── manage-order/ ├── entities/ # 8개 entities └── shared/ ├── lib/ │ ├── formatters/ │ │ └── formatKRW.ts # ₩1,000,000 │ └── validators/ │ └── validatePhone.ts # 010-1234-5678
총 파일: ~120개 | 예상 크기: ~30KB
**추가 생성: 한국형 유틸리티**
```typescript
// shared/lib/formatters/formatKRW.ts
export const formatKRW = (amount: number): string => {
return `₩${amount.toLocaleString('ko-KR')}`;
};
// formatKRW(15000) → "₩15,000"
// shared/lib/validators/validatePhone.ts
export const validateKoreanPhone = (phone: string): boolean => {
return /^010-\d{4}-\d{4}$/.test(phone);
};
난이도: ⭐⭐⭐ 고급
시나리오: 은행 인터넷뱅킹 시스템
요청:
Angular 기반 핀테크 플랫폼을 FSD로 구축해줘.
- 프레임워크: Angular 17 + RxJS
- 상태관리: NgRx
- 기능:
1. 계좌 조회/이체
2. 카드 관리
3. 대출 신청
4. 투자 상품
5. 보안 (OTP, 생체인증)
6. 관리자 (거래 모니터링, 리스크 관리)
- 팀: 12명
- 특수 요구:
- 금융 규제 준수 (전자금융거래법)
- 높은 보안 수준 (암호화, 감사 로그)
- 접근성 (WCAG 2.1 AA)
생성 구조:
src/
├── app/
│ ├── core/
│ │ ├── auth/ # 인증/인가
│ │ ├── security/ # 암호화, 보안
│ │ └── audit/ # 감사 로그
│ └── providers/
├── pages/ # 25개 페이지
├── widgets/ # 30개 위젯
├── features/ # 40개 features
│ ├── account/
│ │ ├── view-balance/
│ │ ├── transfer/
│ │ │ ├── ui/
│ │ │ ├── model/
│ │ │ │ └── transferValidation.ts # 이체 한도, 수수료 검증
│ │ │ ├── api/
│ │ │ │ └── encryptedTransferApi.ts # 암호화 통신
│ │ │ └── index.ts
│ │ └── transaction-history/
│ ├── card/
│ ├── loan/
│ ├── investment/
│ └── security/
│ ├── otp/
│ └── biometric/
├── entities/ # 15개 entities
│ ├── account/
│ │ └── model/
│ │ └── types.ts
│ │ # interface BankAccount { ... regulatoryCompliance }
│ ├── transaction/
│ └── user/
└── shared/
├── lib/
│ ├── crypto/ # 암호화 유틸
│ ├── validators/
│ │ ├── validateAccountNumber.ts
│ │ ├── validateTransferLimit.ts
│ │ └── validateSecurityLevel.ts
│ └── compliance/ # 규제 준수 헬퍼
└── ui/
└── SecureInput/ # 보안 입력 컴포넌트
총 파일: ~350개 | 예상 크기: ~100KB
추가 생성: 금융 규제 준수
// entities/account/model/types.ts
export interface BankAccount {
accountNumber: string; // 계좌번호 (암호화 저장)
balance: number; // 잔액 (KRW)
currency: 'KRW';
accountType: 'CHECKING' | 'SAVINGS' | 'INVESTMENT';
// 전자금융거래법 준수
regulatoryCompliance: {
kycVerified: boolean; // 본인인증 완료
amlCheckDate: Date; // 자금세탁방지 검사일
dailyTransferLimit: number; // 1일 이체 한도
securityLevel: 1 | 2 | 3; // 보안 등급
};
// 감사 로그
auditLog: {
createdAt: Date;
createdBy: string;
lastModifiedAt: Date;
lastAccessedAt: Date;
};
}
// shared/lib/validators/validateTransferLimit.ts
export const validateTransferLimit = (
account: BankAccount,
amount: number
): ValidationResult => {
const { dailyTransferLimit } = account.regulatoryCompliance;
if (amount > dailyTransferLimit) {
return {
isValid: false,
error: `1일 이체 한도(${formatKRW(dailyTransferLimit)})를 초과했습니다.`
};
}
return { isValid: true };
};
난이도: ⭐⭐⭐ 고급
시나리오: 5년 된 MVC 프로젝트 점진적 전환
요청:
기존 React 프로젝트를 FSD로 마이그레이션하는 계획을 세워줘.
현재 상황:
- 코드 규모: 약 80,000 LOC
- 구조: MVC (components/, services/, utils/)
- 문제점:
- components/ 폴더에 300개 파일
- 순환 의존성 20개 이상
- 팀원 간 코드 배치 의견 불일치
- 팀: 8명 (시니어 2, 중급 4, 주니어 2)
- 제약: 서비스 중단 불가, 기능 동결 없음
목표:
- 12주 내 완료
- 기존 기능 100% 유지
- 점진적 전환 (매주 배포)
출력: 12주 상세 마이그레이션 로드맵
# 80k LOC React 프로젝트 FSD 마이그레이션 로드맵 (12주)
## 준비 단계 (Week 0)
### 팀 교육
- [ ] FSD 개념 세미나 (2시간)
- [ ] 실습 워크샵 (4시간)
- [ ] 가이드라인 문서 공유
### 도구 설정
- [ ] Steiger 린터 설치 (경고 모드)
- [ ] 의존성 분석 도구 실행
- [ ] 마이그레이션 스크립트 준비
## Phase 1: Shared 레이어 (Week 1-2)
### Week 1: 분석 및 계획
**작업**:
1. 공통 컴포넌트 분류 (Button, Input, Modal 등 50개)
2. 유틸리티 함수 정리 (formatters, validators 등 30개)
3. 이동 순서 결정 (의존성 낮은 것부터)
**담당**: 시니어 2명
### Week 2: 실행
**작업**:
```bash
# 자동 이동 스크립트 실행
node scripts/migrate-shared.js
# 생성 구조
src/
└── shared/
├── ui/ # 50개 컴포넌트
├── lib/ # 30개 유틸리티
└── api/ # API 클라이언트
검증:
담당: 전체 팀
작업:
// 기존: models/User.ts, services/userService.ts (분산)
// 신규: entities/user/ (통합)
entities/user/
├── model/
│ └── types.ts # User 타입 정의
├── api/
│ └── userApi.ts # API 호출
├── ui/
│ ├── UserCard.tsx # 사용자 카드 컴포넌트
│ └── UserAvatar.tsx
├── lib/
│ └── getUserFullName.ts
└── index.ts # Public API
마이그레이션 대상: User, Product (핵심 도메인)
담당: 시니어 1 + 중급 2
대상: Order, Cart, Payment, Category (5개)
담당: 중급 2 + 주니어 2
작업:
기존:
pages/LoginPage.tsx (로그인 폼 + API + 상태 모두 포함)
신규:
features/auth/
├── login/
│ ├── ui/LoginForm.tsx
│ ├── model/loginSlice.ts
│ ├── api/loginApi.ts
│ └── index.ts
├── signup/
└── logout/
담당: 중급 2명
대상: 15개 주요 Features
담당: 전체 팀 (페어 프로그래밍)
작업: 기존 pages/를 조합 레이어로 단순화
// 기존: HomePage.tsx (600줄 - 로직 포함)
// 신규: pages/home/ui/HomePage.tsx (150줄 - 조합만)
const HomePage = () => {
return (
<>
<Header />
<ProductSearchWidget />
<ProductGridWidget />
<Footer />
</>
);
};
작업: 복합 UI 블록 추출 (Header, ProductGrid, ShoppingCartPreview 등 10개)
// steiger.config.ts
export default defineConfig([
...fsd.configs.recommended,
// 경고 → 에러로 변경
{
rules: {
'fsd/forbidden-imports': 'error', // 기존: 'warn'
'fsd/no-cross-slice-dependency': 'error'
}
}
]);
# .github/workflows/ci.yml
- name: Architecture Lint
run: npm run lint:arch # Steiger 검증
| 리스크 | 확률 | 영향 | 완화 전략 |
|---|---|---|---|
| 서비스 장애 | 낮음 | 높음 | 매주 배포, 롤백 계획, 카나리 배포 |
| 팀원 저항 | 중간 | 중간 | 충분한 교육, 페어 프로그래밍, 점진적 적용 |
| 일정 지연 | 중간 | 중간 | 버퍼 2주 확보, 우선순위 조정 |
---
### Example 5: 멀티 프레임워크 모노레포
**난이도**: ⭐⭐⭐⭐ 전문가
**시나리오**: React(고객용) + Vue(관리자) 통합 프로젝트
**요청**:
모노레포 환경에서 FSD를 적용해줘.
구조:
요구사항:
**생성 구조**:
monorepo/ ├── apps/ │ ├── customer-web/ # React 앱 │ │ └── src/ │ │ ├── app/ │ │ ├── pages/ │ │ ├── widgets/ │ │ ├── features/ │ │ ├── entities/ # 고객용 entities │ │ └── shared/ # 앱 전용 shared │ │ │ └── admin-panel/ # Vue 앱 │ └── src/ │ ├── app/ │ ├── pages/ │ ├── widgets/ │ ├── features/ │ ├── entities/ # 관리자용 entities │ └── shared/ │ ├── packages/ │ ├── shared-entities/ # 공통 도메인 객체 │ │ ├── user/ │ │ ├── product/ │ │ └── order/ │ │ │ ├── shared-ui/ # 공통 UI 라이브러리 │ │ ├── Button/ │ │ └── Input/ │ │ │ └── shared-logic/ # 공통 비즈니스 로직 │ ├── validators/ │ └── formatters/ │ ├── steiger.config.ts # 모노레포 전체 린터 설정 ├── package.json └── turbo.json # Turborepo 설정
**Steiger 설정 (모노레포)**:
```typescript
// steiger.config.ts
import { defineConfig } from 'steiger';
import fsd from '@feature-sliced/steiger-plugin';
export default defineConfig([
// 각 앱에 FSD 규칙 적용
{
files: ['./apps/*/src/**'],
...fsd.configs.recommended
},
// packages/는 FSD 규칙 예외
{
files: ['./packages/**'],
rules: {
'fsd/forbidden-imports': 'off'
}
}
]);
난이도: ⭐⭐⭐⭐ 전문가
시나리오: 병원 전자의무기록(EMR) 시스템
요청:
의료 도메인 FSD 프로젝트를 구축해줘.
특수 요구사항:
- HIPAA 규정 준수 (환자 데이터 암호화, 접근 로그)
- 의료 용어 정확성
- 높은 가용성 (99.9% 업타임)
- 감사 추적 (모든 데이터 변경 기록)
기능:
- 환자 관리 (등록, 차트, 기록)
- 진료 (예약, 접수, 진단)
- 처방전 (약물, 검사)
- 청구 (보험, 수납)
생성 구조 (핵심 부분):
src/
├── entities/
│ ├── patient/
│ │ ├── model/
│ │ │ └── types.ts
│ │ │ # interface Patient {
│ │ │ # hipaaCompliance: {
│ │ │ # consentGiven: boolean
│ │ │ # dataEncrypted: boolean
│ │ │ # accessLog: AccessLog[]
│ │ │ # }
│ │ │ # }
│ │ ├── api/
│ │ │ └── patientApi.ts # 암호화 통신
│ │ └── lib/
│ │ ├── validateMRN.ts # 의료기록번호 검증
│ │ └── anonymizePatient.ts
│ │
│ ├── prescription/
│ │ └── model/
│ │ └── drugInteraction.ts # 약물 상호작용 검사
│ │
│ └── insurance/
│ └── lib/
│ └── verifyInsurance.ts # 보험 확인
│
├── features/
│ ├── patient/
│ │ ├── register/
│ │ │ ├── ui/PatientRegistrationForm.tsx
│ │ │ ├── model/
│ │ │ │ └── hipaaValidation.ts
│ │ │ └── api/
│ │ │ └── encryptedRegistrationApi.ts
│ │ └── view-chart/
│ │ └── model/
│ │ └── accessControl.ts # 권한 기반 접근
│ │
│ └── prescription/
│ └── create/
│ └── model/
│ └── drugSafetyCheck.ts
│
└── shared/
├── lib/
│ ├── crypto/ # HIPAA 준수 암호화
│ │ ├── encryptPHI.ts # Protected Health Information
│ │ └── auditLog.ts
│ ├── validators/
│ │ ├── validateNPI.ts # 의사면허번호
│ │ └── validateInsuranceID.ts
│ └── medical/
│ ├── icd10Codes.ts # 질병 코드
│ └── cptCodes.ts # 의료 행위 코드
│
└── ui/
└── SecureDisplay/ # 민감 정보 표시 컴포넌트
HIPAA 준수 예시 코드:
// entities/patient/model/types.ts
export interface Patient {
// 기본 정보
id: string;
mrn: string; // Medical Record Number (암호화)
firstName: string; // 암호화
lastName: string; // 암호화
dateOfBirth: Date; // 암호화
// HIPAA 규정 준수
hipaaCompliance: {
consentGiven: boolean; // 동의서 수령
consentDate: Date;
dataEncryptedAtRest: boolean; // 저장 데이터 암호화
dataEncryptedInTransit: boolean; // 전송 데이터 암호화
// 접근 로그 (필수)
accessLog: Array<{
accessedBy: string; // 접근자 ID
accessedAt: Date;
purpose: string; // 접근 목적
ipAddress: string;
action: 'VIEW' | 'EDIT' | 'DELETE';
}>;
// 감사 추적
auditTrail: Array<{
changedBy: string;
changedAt: Date;
fieldChanged: string;
oldValue: string; // 암호화
newValue: string; // 암호화
}>;
};
// 보험 정보
insurance: {
provider: string;
policyNumber: string; // 암호화
verifiedAt: Date;
};
}
// shared/lib/crypto/encryptPHI.ts
import CryptoJS from 'crypto-js';
const ENCRYPTION_KEY = process.env.VITE_PHI_ENCRYPTION_KEY!;
export const encryptPHI = (data: string): string => {
// AES-256 암호화 (HIPAA 요구사항)
const encrypted = CryptoJS.AES.encrypt(data, ENCRYPTION_KEY);
return encrypted.toString();
};
export const decryptPHI = (encrypted: string): string => {
const decrypted = CryptoJS.AES.decrypt(encrypted, ENCRYPTION_KEY);
return decrypted.toString(CryptoJS.enc.Utf8);
};
// features/patient/register/model/hipaaValidation.ts
export const validateHIPAACompliance = (
patient: PatientRegistrationData
): ValidationResult => {
const errors: string[] = [];
// 동의서 필수
if (!patient.consentGiven) {
errors.push('환자 동의서가 필요합니다.');
}
// 최소 나이 확인 (자가 동의)
const age = calculateAge(patient.dateOfBirth);
if (age < 18 && !patient.guardianConsent) {
errors.push('미성년자는 보호자 동의가 필요합니다.');
}
// 보험 정보 필수
if (!patient.insurance) {
errors.push('보험 정보가 필요합니다.');
}
return {
isValid: errors.length === 0,
errors
};
};
난이도: ⭐⭐ 중급
시나리오: 한국 B2B SaaS 스타트업
요청:
한국 시장 맞춤형 FSD 프로젝트를 만들어줘.
특징:
- 한국어 우선 (다국어 추후)
- KRW 통화
- 한국 주소 체계
- 휴대폰 번호 010-XXXX-XXXX
- 사업자등록번호
- 공휴일 캘린더
프레임워크: React + TypeScript
기능: B2B 견적/계약 관리
생성 구조 (한국 특화 부분):
src/
├── entities/
│ ├── company/
│ │ └── model/
│ │ └── types.ts
│ │ # interface KoreanCompany {
│ │ # businessNumber: string # 사업자등록번호
│ │ # address: KoreanAddress
│ │ # phone: string # 02-XXXX-XXXX
│ │ # }
│ │
│ └── contract/
│ └── model/
│ └── types.ts
│ # interface Contract {
│ # amount: number # KRW
│ # taxRate: 0.1 # 부가세 10%
│ # paymentTerms: '선불' | '후불' | '월말정산'
│ # }
│
└── shared/
├── lib/
│ ├── formatters/
│ │ ├── formatKRW.ts
│ │ │ # formatKRW(15000) → "₩15,000"
│ │ │ # formatKRW(1500000) → "₩1,500,000" 또는 "150만원"
│ │ ├── formatAddress.ts
│ │ │ # "서울특별시 강남구 테헤란로 123"
│ │ └── formatBusinessNumber.ts
│ │ # "123-45-67890"
│ │
│ ├── validators/
│ │ ├── validatePhone.ts
│ │ │ # 010-1234-5678, 02-123-4567, 1588-0000
│ │ ├── validateBusinessNumber.ts
│ │ │ # 체크섬 검증 포함
│ │ └── validateKoreanAddress.ts
│ │
│ └── calendar/
│ ├── koreanHolidays.ts
│ │ # 신정, 설날, 삼일절, 어린이날, ...
│ └── isBusinessDay.ts
│ # 주말 + 공휴일 제외
│
├── config/
│ ├── i18n.ts
│ │ # 한국어 기본, 영어 fallback
│ └── constants.ts
│ # VAT_RATE = 0.1
│ # BUSINESS_HOURS = { start: 9, end: 18 }
│
└── ui/
├── AddressInput/ # 주소 검색 (카카오/네이버 API)
└── PhoneInput/ # 자동 하이픈 삽입
한국 특화 코드:
// shared/lib/formatters/formatKRW.ts
export const formatKRW = (
amount: number,
options?: { short?: boolean }
): string => {
if (options?.short && amount >= 10000) {
// 1만원 이상 → "만원" 표기
const man = Math.floor(amount / 10000);
const remainder = amount % 10000;
if (remainder === 0) {
return `₩${man}만원`;
} else {
return `₩${man}만 ${remainder.toLocaleString('ko-KR')}원`;
}
}
return `₩${amount.toLocaleString('ko-KR')}`;
};
// 예시:
// formatKRW(15000) → "₩15,000"
// formatKRW(15000, { short: true }) → "₩1만 5,000원"
// formatKRW(1500000) → "₩1,500,000"
// formatKRW(1500000, { short: true }) → "₩150만원"
// shared/lib/validators/validateBusinessNumber.ts
export const validateBusinessNumber = (num: string): boolean => {
// 형식: XXX-XX-XXXXX
const cleaned = num.replace(/-/g, '');
if (!/^\d{10}$/.test(cleaned)) {
return false;
}
// 체크섬 검증 (국세청 알고리즘)
const keys = [1, 3, 7, 1, 3, 7, 1, 3, 5];
let sum = 0;
for (let i = 0; i < 9; i++) {
sum += parseInt(cleaned[i]) * keys[i];
}
sum += Math.floor((parseInt(cleaned[8]) * 5) / 10);
const checkDigit = (10 - (sum % 10)) % 10;
return checkDigit === parseInt(cleaned[9]);
};
// shared/lib/calendar/koreanHolidays.ts
export const KOREAN_HOLIDAYS_2025 = [
{ date: '2025-01-01', name: '신정' },
{ date: '2025-01-28', name: '설날 연휴' },
{ date: '2025-01-29', name: '설날' },
{ date: '2025-01-30', name: '설날 연휴' },
{ date: '2025-03-01', name: '삼일절' },
{ date: '2025-05-05', name: '어린이날' },
{ date: '2025-05-06', name: '어린이날 대체공휴일' },
{ date: '2025-06-06', name: '현충일' },
{ date: '2025-08-15', name: '광복절' },
{ date: '2025-10-03', name: '개천절' },
{ date: '2025-10-05', name: '추석 연휴' },
{ date: '2025-10-06', name: '추석' },
{ date: '2025-10-07', name: '추석 연휴' },
{ date: '2025-10-08', name: '추석 대체공휴일' },
{ date: '2025-10-09', name: '한글날' },
{ date: '2025-12-25', name: '크리스마스' },
];
export const isKoreanHoliday = (date: Date): boolean => {
const dateStr = date.toISOString().split('T')[0];
return KOREAN_HOLIDAYS_2025.some(h => h.date === dateStr);
};
export const isBusinessDay = (date: Date): boolean => {
const dayOfWeek = date.getDay();
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
return !isWeekend && !isKoreanHoliday(date);
};
// entities/company/model/types.ts
export interface KoreanAddress {
postalCode: string; // 우편번호 (5자리)
sido: string; // 시/도
sigungu: string; // 시/군/구
roadName: string; // 도로명
buildingNumber: string; // 건물번호
detailAddress?: string; // 상세주소
// 지번 주소 (옵션)
jibunAddress?: {
dong: string; // 동
li: string; // 리
jibun: string; // 지번
};
}
export interface KoreanCompany {
id: string;
name: string;
businessNumber: string; // 사업자등록번호 (XXX-XX-XXXXX)
corporateNumber?: string; // 법인등록번호 (대기업)
ceoName: string;
address: KoreanAddress;
phone: string; // 02-XXX-XXXX or 010-XXXX-XXXX
fax?: string;
email: string;
industry: string; // 업종
businessType: string; // 업태
}
모든 슬라이스는 index.ts로만 외부 노출
// features/auth/login/index.ts
export { LoginForm } from './ui/LoginForm';
export { useLogin } from './model/useLogin';
export type { LoginCredentials } from './model/types';
// ❌ 다른 파일 직접 import 금지
// import { validate } from 'features/auth/login/lib/validate'; // 나쁜 예
// ✅ Public API 사용
// import { LoginForm, useLogin } from 'features/auth/login'; // 좋은 예
상위 레이어는 하위만 참조
// ✅ 올바른 의존성
// pages → widgets, features, entities, shared
// features → entities, shared
// entities → shared
// ❌ 잘못된 의존성
// entities → features (하위가 상위 참조)
// shared → entities (Shared는 외부 라이브러리만)
CI/CD에 통합하여 자동 검증
# .github/workflows/ci.yml
- name: Architecture Lint
run: npm run lint:arch
재사용되지 않는 코드는 pages에 먼저 배치
// 특정 페이지에서만 쓰이는 로직 → pages/
// pages/dashboard/model/useDashboardData.ts
// 여러 곳에서 재사용 → features/
// features/analytics/get-stats/
슬라이스명은 비즈니스 용어 사용
✅ features/cart/add-to-cart (명확)
❌ features/cart/add (모호)
✅ entities/order (명확)
❌ entities/data (너무 일반적)
// ❌ 나쁜 예
// features/cart/add-item/ui/AddButton.tsx
import { useWishlist } from 'features/wishlist/toggle'; // 같은 레이어!
// ✅ 좋은 예
// 공통 로직은 entities 또는 shared로 이동
// entities/product/lib/useProductActions.ts
// ❌ 너무 세분화
features/user/
├── get-name/
├── get-email/
├── get-avatar/
└── get-status/
// ✅ 적절한 그룹화
entities/user/
├── model/types.ts
├── api/userApi.ts
└── lib/getUserInfo.ts
// ❌ 나쁜 예
// shared/lib/calculateOrderTotal.ts // 비즈니스 로직
// ✅ 좋은 예
// features/order/calculate-total/lib/calculateTotal.ts
// shared/lib/sum.ts // 순수 유틸리티만
// ❌ 나쁜 예
import { validate } from 'features/auth/login/lib/validate';
// ✅ 좋은 예
import { validateLogin } from 'features/auth/login';
// ❌ 나쁜 예
// widgets/dashboard/ (3000줄 - 너무 복잡)
// ✅ 좋은 예
// widgets/dashboard-stats/
// widgets/dashboard-chart/
// widgets/dashboard-actions/
증상:
npm run lint:arch
❌ features/cart/add-item imports from features/wishlist
Rule: fsd/no-cross-slice-dependency
원인: 동일 레이어(features) 슬라이스 간 직접 참조
해결책:
// 방법 1: 공통 로직을 entities로 이동
// entities/product/lib/useProductActions.ts
export const useProductActions = () => {
const addToCart = () => { /* ... */ };
const addToWishlist = () => { /* ... */ };
return { addToCart, addToWishlist };
};
// features/cart/add-item/ui/AddButton.tsx
import { useProductActions } from 'entities/product';
const { addToCart } = useProductActions();
// features/wishlist/toggle/ui/WishlistButton.tsx
import { useProductActions } from 'entities/product';
const { addToWishlist } = useProductActions();
// 방법 2: 상위 레이어(widgets, pages)에서 조합
// widgets/product-card/ui/ProductCard.tsx
import { AddToCartButton } from 'features/cart/add-item';
import { WishlistButton } from 'features/wishlist/toggle';
<ProductCard>
<AddToCartButton />
<WishlistButton />
</ProductCard>
증상:
❌ app/index.tsx imports from features/auth/login/ui/LoginForm
Rule: fsd/no-public-api-sidestep
Should import from: features/auth/login
원인: 내부 파일 직접 import
해결책:
// features/auth/login/index.ts (Public API 정의)
export { LoginForm } from './ui/LoginForm';
export { useLogin } from './model/useLogin';
export type { LoginCredentials } from './model/types';
// app/index.tsx (수정 후)
import { LoginForm } from 'features/auth/login'; // ✅
증상:
Error: Circular dependency detected
features/cart → entities/product → features/cart
원인: 양방향 참조
해결책:
// ❌ 나쁜 예
// entities/product/ui/ProductCard.tsx
import { AddToCartButton } from 'features/cart/add-item'; // 상위 참조!
// ✅ 좋은 예
// 방법 1: Slot Pattern (React)
// entities/product/ui/ProductCard.tsx
interface Props {
children?: React.ReactNode; // 슬롯 제공
}
// pages/home/ui/HomePage.tsx (상위에서 조합)
<ProductCard>
<AddToCartButton />
</ProductCard>
// 방법 2: Callback 전달
// entities/product/ui/ProductCard.tsx
interface Props {
onAddToCart: (id: string) => void;
}
// pages/home/ui/HomePage.tsx
const handleAddToCart = (id: string) => {
// features/cart 로직 호출
};
<ProductCard onAddToCart={handleAddToCart} />
증상: 기존 코드와 FSD 구조가 섞여 혼란
해결책:
프로젝트 구조:
src/
├── legacy/ # 기존 코드 (점진적 마이그레이션)
│ ├── components/
│ └── services/
│
├── app/ # FSD 구조 (신규 코드)
├── pages/
├── widgets/
├── features/
├── entities/
└── shared/
steiger.config.ts:
{
files: ['./src/legacy/**'],
rules: {
'fsd/forbidden-imports': 'off' # 레거시는 규칙 완화
}
}
마이그레이션 전략:
증상: 특정 코드를 widgets에 둘지 features에 둘지 판단 어려움
판단 기준:
Feature (비즈니스 기능 = UI + 인터랙션):
- 사용자가 "~을 한다"로 표현 가능
- 예: "상품을 장바구니에 추가한다", "로그인한다"
- 구조: ui/ + model/ + api/
Widget (복합 UI 블록 = 조합 + 표현):
- "~을 보여준다"로 표현 가능
- 예: "대시보드를 보여준다", "헤더를 보여준다"
- 구조: ui/ (주로), model/ (상태만)
구체적 예시:
✅ Feature: features/cart/add-to-cart
- AddToCartButton (UI)
- addToCartSlice (상태)
- addToCartApi (API)
✅ Widget: widgets/product-grid
- ProductGrid (UI 조합)
- useGridLayout (레이아웃 상태)
- 여러 features 사용 (검색, 필터, 추가)
❓ 애매한 경우: "상품 검색 바"
→ Widget: 검색 UI 블록만 (입력창 + 버튼)
→ Feature: 검색 로직 (features/product/search)
→ 결론: Widget이 Feature 사용
증상:
// 상대 경로 지옥
import { Button } from '../../../../shared/ui/Button';
해결책:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@app/*": ["src/app/*"],
"@pages/*": ["src/pages/*"],
"@widgets/*": ["src/widgets/*"],
"@features/*": ["src/features/*"],
"@entities/*": ["src/entities/*"],
"@shared/*": ["src/shared/*"]
}
}
}
// vite.config.ts (Vite 사용 시)
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@app': path.resolve(__dirname, './src/app'),
'@pages': path.resolve(__dirname, './src/pages'),
'@widgets': path.resolve(__dirname, './src/widgets'),
'@features': path.resolve(__dirname, './src/features'),
'@entities': path.resolve(__dirname, './src/entities'),
'@shared': path.resolve(__dirname, './src/shared'),
}
}
});
// 사용 예시
import { Button } from '@shared/ui/Button';
import { useLogin } from '@features/auth/login';
증상:
npm install -D steiger @feature-sliced/steiger-plugin
Error: Cannot find module 'steiger'
해결책:
# 1. 캐시 정리
npm cache clean --force
# 2. node_modules 삭제 후 재설치
rm -rf node_modules package-lock.json
npm install
# 3. Steiger 재설치
npm install -D steiger@latest @feature-sliced/steiger-plugin@latest
# 4. 설치 확인
npx steiger --version
# 5. 여전히 안 되면 yarn 또는 pnpm 시도
yarn add -D steiger @feature-sliced/steiger-plugin
# 또는
pnpm add -D steiger @feature-sliced/steiger-plugin
증상:
❌ shared/ui/Button imports from shared/lib/theme
Rule: fsd/no-public-api-sidestep
원인: Shared 내부에서는 자유로운 참조 가능해야 함
해결책:
// steiger.config.ts
import { defineConfig } from 'steiger';
import fsd from '@feature-sliced/steiger-plugin';
export default defineConfig([
...fsd.configs.recommended,
{
files: ['./src/shared/**'],
rules: {
// Shared 내부는 Public API 규칙 완화
'fsd/no-public-api-sidestep': 'off',
'fsd/no-cross-slice-dependency': 'off'
}
}
]);
증상: 한글 폴더/파일명 사용 시 일부 도구에서 오류
권장 사항:
❌ 나쁜 예:
features/로그인/
entities/사용자/
✅ 좋은 예:
features/auth/login/ # 영문 폴더명
entities/user/ # 영문 폴더명
├── model/
│ └── types.ts # 내부 코드는 한글 주석 가능
│ # interface 사용자 { ... }
이유:
증상: 각자 다른 레이어에 코드 배치
해결책:
# ARCHITECTURE.md (팀 가이드라인)
## 레이어 배치 결정 트리
### 1. 외부 라이브러리 래퍼인가?
YES → shared/
NO → 다음 단계
### 2. 도메인 객체인가? (User, Product, Order)
YES → entities/
NO → 다음 단계
### 3. 사용자 인터랙션이 있는가?
YES → features/
NO → 다음 단계
### 4. 복수의 features 조합인가?
YES → widgets/
NO → 다음 단계
### 5. 특정 페이지에서만 쓰이는가?
YES → pages/
NO → 재검토 (애매하면 Shared)
## 예시
- formatPrice → shared/lib (순수 유틸리티)
- User 타입 → entities/user (도메인)
- 로그인 폼 → features/auth/login (인터랙션)
- 헤더 → widgets/header (조합)
- 홈페이지 → pages/home (페이지)
팀 컨벤션:
이 Skill은 자연어 대화 기반이므로 별도 API가 없습니다.
하지만 생성되는 코드에서 자주 사용되는 패턴들을 문서화합니다.
// shared/types/fsd.ts
/**
* FSD 레이어 타입
*/
export type FSDLayer =
| 'app'
| 'pages'
| 'widgets'
| 'features'
| 'entities'
| 'shared';
/**
* FSD 세그먼트 타입
*/
export type FSDSegment =
| 'ui' // UI 컴포넌트
| 'model' // 상태 관리, 비즈니스 로직
| 'api' // API 호출
| 'lib' // 헬퍼 함수
| 'config'; // 설정
/**
* 슬라이스 메타데이터
*/
export interface SliceMetadata {
layer: FSDLayer;
sliceName: string;
segments: FSDSegment[];
dependencies: string[]; // 다른 슬라이스 참조 목록
}
// features/auth/login/index.ts
// 1. 컴포넌트 export
export { LoginForm } from './ui/LoginForm';
// 2. Hooks export
export { useLogin } from './model/useLogin';
// 3. 타입 export
export type { LoginCredentials, LoginResponse } from './model/types';
// 4. 상수 export
export { LOGIN_ERROR_MESSAGES } from './config/constants';
// ❌ 내부 구현 export 금지
// export { validateEmail } from './lib/validate'; // 나쁜 예
// shared/lib/fsd/createSlice.ts
interface CreateSliceOptions {
layer: FSDLayer;
name: string;
segments: FSDSegment[];
}
/**
* FSD 슬라이스 폴더 구조 자동 생성
*/
export const createSlice = (options: CreateSliceOptions) => {
const { layer, name, segments } = options;
const basePath = `src/${layer}/${name}`;
// 폴더 생성
segments.forEach(segment => {
fs.mkdirSync(`${basePath}/${segment}`, { recursive: true });
});
// index.ts 생성
fs.writeFileSync(
`${basePath}/index.ts`,
`// Public API for ${layer}/${name}\n`
);
return basePath;
};
// 사용 예시:
createSlice({
layer: 'features',
name: 'auth/login',
segments: ['ui', 'model', 'api']
});
추천 확장:
설치:
code --install-extension steiger-vscode
code --install-extension fsd-helper
code --install-extension christian-kohler.path-intellisense
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
// 기존 규칙...
],
rules: {
// FSD 관련 커스텀 규칙 (선택)
'no-restricted-imports': ['error', {
patterns: [
{
group: ['../*/*'],
message: '상대 경로 대신 @ alias 사용하세요.'
}
]
}]
}
};
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
architecture-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Architecture Lint (Steiger)
run: npm run lint:arch
- name: Fail on violations
if: failure()
run: echo "FSD 규칙 위반 발견. PR을 병합할 수 없습니다."
코드 분할:
// app/providers/router.tsx
import { lazy, Suspense } from 'react';
// 페이지별 lazy loading
const HomePage = lazy(() => import('@pages/home'));
const ProductPage = lazy(() => import('@pages/product-detail'));
export const AppRouter = () => (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/product/:id" element={<ProductPage />} />
</Routes>
</Suspense>
);
번들 크기 모니터링:
// package.json
{
"scripts": {
"analyze": "vite build --mode analyze",
"build:check": "npm run build && npm run analyze"
}
}
단계별 가이드: Example 4 참조
주요 원칙:
/legacy 폴더로 분리Initial Release
Features:
Documentation:
A:
| 구분 | FSD | Clean Architecture |
|---|---|---|
| 출처 | 프론트엔드 전용 | 백엔드 중심 |
| 계층 | 7개 (app~shared) | 4개 (Entities/Use Cases/Interface/Framework) |
| 의존성 규칙 | 단방향 (상위→하위) | 의존성 역전 (모든 방향 제어) |
| 도구 지원 | Steiger 린터 | 없음 (직접 구현) |
| 학습 곡선 | 중간 (2~3주) | 높음 (4주+) |
| 적합 분야 | 프론트엔드 | 백엔드, 복잡한 시스템 |
결론: 프론트엔드 프로젝트라면 FSD 권장
A: 권장하지 않습니다.
기준:
대안:
A: 네, 가능하지만 조정 필요합니다.
Next.js 예시:
app/ # Next.js App Router
├── (routes)/
│ ├── page.tsx # pages/home 역할
│ └── product/[id]/
│ └── page.tsx # pages/product-detail 역할
│
src/ # FSD 구조
├── widgets/
├── features/
├── entities/
└── shared/
핵심 원칙:
app/ 폴더는 라우팅만src/ 내 FSD 구조에A: 단계적 교육 + 점진적 도입
교육 계획 (1주):
도입 전략:
A: 현재 Steiger가 공식 도구입니다.
과거 도구:
@feature-sliced/eslint-config (Deprecated, Steiger로 대체)대안:
이 Skill 개선에 기여하려면:
피드백 제공
예시 추가
문서 개선
이 Skill 문서는 MIT License입니다.
생성된 코드는 사용자 소유이며 자유롭게 사용 가능합니다.
Feature-Sliced Design 방법론은 오픈소스 커뮤니티 프로젝트입니다.
Version: 1.0.0
Last Updated: 2025-01-24
Compatibility: Claude 3.5 Sonnet+, Claude.ai, Claude Code v1.0.0+
Skill Type: Orchestrator + Generator + Validator
축하합니다! 이제 Feature-Sliced Design으로 확장 가능한 프론트엔드 아키텍처를 구축할 준비가 되었습니다. 🚀
질문이나 피드백은 언제든지 환영합니다!
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience