소스 정보
- 저장소
- puk0806/gugbab-claude
- 최근 소스 활동
- 2026년 6월 26일 07:16
- 감지된 SKILL.md 언어
- 한국어
- 스타
- 2
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/puk0806/gugbab-claude --skill ingredient-management명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
DDD(Domain-Driven Design) 아키텍처 핵심 패턴 - 유비쿼터스 언어, 서브도메인, 바운디드 컨텍스트, Aggregate, Entity/VO, 도메인 서비스/이벤트, 레이어드 아키텍처
대규모 React/Next.js 프로젝트를 layer-first(types/·utils/·hooks/·api/·components/ 밑에 도메인이 반복되는 구조)에서 domain-first(feature/도메인 우선) 구조로 전환하는 설계 기준과 절차. Feature-Sliced Design 2.1 정본(layers 6종·slices·segments·import 규칙·@x 크로스임포트·public API), FSD를 쓰지 않는 경량 대안(features + shared 2~3계층 + ESLint import/no-restricted-paths), Next.js App Router 공존 전략(route group `()`·private folder `_`·colocation), Turborepo/Nx 모노레포에서 폴더↔패키지 승격 기준, colocation과 배럴 파일 성능 트레이드오프, 도메인 경계 역추출(import 그래프·change coupling·용어 클러스터), 전환 실패 패턴(shared 비대화·entities 남용·순환 의존·도메인=라우트 착각·조기 추상화). 도메인 개념 자체(바운디드 컨텍스트·유비쿼터스 언어)는 `architecture/ddd` 스킬을 참조한다.
소스 파일 수천 개 규모 프론트엔드 코드베이스를 멈추지 않고 점진 재구조화하는 실행 전략 - Strangler Fig / Branch by Abstraction / Parallel Change, ts-morph·jscodeshift codemod, PR 분할·검증 게이트·되돌리기, 테스트 없는 코드의 안전망, 작업 순서 설계와 위반 수 기반 진행 추적
| name | ingredient-management |
| description | 식재료 관리 도메인 모델 — 보관 위치·카테고리·소비기한·수량 관리 패턴. PWA 오프라인 앱용 로컬 상태 설계 포함. |
소스: 국내 식재료 관리 앱(유통기한 언제지·원더 프리지·BEEP) 도메인 분석 검증일: 2026-06-26
interface Ingredient {
id: string; // UUID
name: string; // 식재료명 (예: "닭가슴살")
category: IngredientCategory; // 식품 분류
storageLocation: StorageLocation; // 보관 위치
quantity: number; // 수량
unit: IngredientUnit; // 단위
purchaseDate: string; // 구매일 (ISO 8601)
expiryDate?: string; // 소비기한 (없으면 undefined)
memo?: string; // 메모
createdAt: string;
updatedAt: string;
}
type IngredientCategory =
| 'grain' // 곡류·서류 (쌀, 감자, 고구마)
| 'vegetable' // 채소류
| 'fruit' // 과일류
| 'meat' // 육류
| 'seafood' // 어패류
| 'egg_dairy' // 난류·유제품
| 'bean_nut' // 콩류·견과류
| 'processed' // 가공식품
| 'sauce' // 양념·소스
| 'other'; // 기타
type StorageLocation =
| 'fridge' // 냉장
| 'freezer' // 냉동
| 'pantry' // 상온 (식료품 창고·찬장)
| 'counter'; // 실온 (바나나·토마토 등)
type IngredientUnit =
| 'g' // 그램
| 'kg' // 킬로그램
| 'ml' // 밀리리터
| 'l' // 리터
| 'ea' // 개 (개수)
| 'pack' // 팩
| 'can' // 캔
| 'bag'; // 봉지
type IngredientStatus =
| 'fresh' // 신선 (소비기한 7일 이상)
| 'warning' // 임박 (소비기한 3~7일)
| 'urgent' // 주의 (소비기한 3일 이내)
| 'expired' // 만료
| 'no_expiry'; // 소비기한 없음 (장기 보관 가능)
const getIngredientStatus = (ingredient: Ingredient): IngredientStatus => {
if (!ingredient.expiryDate) return 'no_expiry';
const today = new Date();
const expiry = new Date(ingredient.expiryDate);
const daysLeft = Math.ceil((expiry.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
if (daysLeft < 0) return 'expired';
if (daysLeft <= 3) return 'urgent';
if (daysLeft <= 7) return 'warning';
return 'fresh';
};
| 식재료 | 냉장 | 냉동 | 상온 |
|---|---|---|---|
| 생닭 | 2일 | 9개월 | — |
| 소·돼지고기 | 3~5일 | 4~6개월 | — |
| 생선(생) | 1~2일 | 6개월 | — |
| 달걀 | 3~5주 | — | 1~2주 |
| 우유 | 개봉 후 5~7일 | — | — |
| 배추김치 | 1~2개월 | 6개월 | — |
| 밥 | 3~4일 | 1개월 | — |
| 감자·고구마 | 1~2주 | — | 1~2주 (서늘한 곳) |
| 양파 | 1~2개월 | — | 1~2개월 |
| 마늘 | 3개월 | 6~12개월 | 2~4주 |
주의: 위 수치는 일반적인 참고값이며 개봉·조리 여부에 따라 달라짐
// Dexie 스키마
class FridgeDatabase extends Dexie {
ingredients!: Table<Ingredient>;
constructor() {
super('FridgeDB');
this.version(1).stores({
// 인덱스: id(primary), category, storageLocation, expiryDate
ingredients: '++id, category, storageLocation, expiryDate',
});
}
}
// 소비기한 임박 순 정렬
const getSortedByExpiry = () =>
db.ingredients
.where('expiryDate')
.above('') // expiryDate 있는 것만
.sortBy('expiryDate');
// 위치별 필터
const getByLocation = (location: StorageLocation) =>
db.ingredients.where('storageLocation').equals(location).toArray();
// 카테고리별 필터
const getByCategory = (category: IngredientCategory) =>
db.ingredients.where('category').equals(category).toArray();
// 전체 (소비기한 만료 제외)
const getAvailable = async () => {
const all = await db.ingredients.toArray();
const today = new Date().toISOString().split('T')[0];
return all.filter( !i. || i. >= today);
};
식단 추천 AI에 넘길 식재료 컨텍스트 포맷:
const buildIngredientContext = async (): Promise<string> => {
const available = await getAvailable();
// 상태별 그룹핑
const urgent = available.filter(i => getIngredientStatus(i) === 'urgent');
const warning = available.filter(i => getIngredientStatus(i) === 'warning');
const fresh = available.filter(i =>
['fresh', 'no_expiry'].includes(getIngredientStatus(i))
);
const format = (items: Ingredient[]) =>
items.map(i => `${i.name} (${i.quantity}${i.unit})`).join(', ');
return `
[빨리 써야 하는 식재료 (3일 이내)]
${urgent.length > 0 ? format(urgent) : '없음'}
[곧 사용해야 하는 식재료 (7일 이내)]
${warning.length > 0 ? format(warning) : '없음'}
[보유 중인 식재료]
${fresh.length > 0 ? format(fresh) : }
`.();
};
| 카테고리 | 이모지 | 한글명 |
|---|---|---|
| grain | 🌾 | 곡류·서류 |
| vegetable | 🥦 | 채소류 |
| fruit | 🍎 | 과일류 |
| meat | 🥩 | 육류 |
| seafood | 🐟 | 어패류 |
| egg_dairy | 🥚 | 난류·유제품 |
| bean_nut | 🫘 | 콩류·견과류 |
| processed | 🥫 | 가공식품 |
| sauce | 🧂 | 양념·소스 |
| other | 📦 | 기타 |
| 상황 | 트리거 시점 | 알림 내용 |
|---|---|---|
| 소비기한 임박 | D-3, D-1 | "[식재료명] 소비기한이 N일 남았어요" |
| 소비기한 당일 | D-day | "[식재료명] 오늘까지 사용하세요" |
| 재고 부족 | quantity ≤ 임계값 | "[식재료명] 재고가 얼마 남지 않았어요" |