基于 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 ≤ 임계값 | "[식재료명] 재고가 얼마 남지 않았어요" |