← 문서 목록

Functional Specification

Energy Meal 기능명세서 v1

프로젝트
Energy Meal — 사주 컨셉 기반 오늘의 메뉴 추천 서비스
문서 버전
v1.0 (구버전 — 기능명세서 v2로 대체됨)
기준일
2026-04-23 (v1 개발 완료 시점 기준)
범위
web/ — Next.js 웹 애플리케이션 (RN WebView 셸 app/은 임베드 대응 항목만 포함)
다음 버전
기능명세서 v2 — 사주팔자 · 오행 엔진 고도화 (Draft)

1.서비스 개요

Energy Meal은 사용자의 생년월일 · 태어난 시간 · 성별 · 양력/음력 정보를 입력받아, 사주 컨셉의 "기운" 해석을 바탕으로 아침 / 점심 / 저녁 시간대별 오늘의 한 끼를 추천하는 모바일 웹 서비스입니다.

2.기술 스택

영역기술용도
프레임워크Next.js 16.2.3 (App Router), React 19.2.4, TypeScript페이지 라우팅 · 렌더링
스타일Tailwind CSS 4, clsx + tailwind-merge유틸리티 기반 스타일링
애니메이션Motion 12화면 전환 · 카드 등장 애니메이션
폼 · 검증React Hook Form 7 + Zod 4입력 폼 상태 관리 · 스키마 검증
날짜dayjs (customParseFormat 플러그인)생년월일 파싱 · 현재 시각 판정
저장소localStorage (추상화 모듈 lib/storage.ts 경유)사용자 입력 영속화
테스트Vitest, React Testing Library, Playwright단위 · 컴포넌트 · E2E 테스트
품질ESLint, Husky + lint-staged커밋 전 린트 · 관련 테스트 자동 실행

3.화면 구성 및 사용자 흐름

온보딩 /서비스 소개
[시작하기]
정보 입력 /setup생년월일 · 성별
양/음력 · 태어난 시간
오늘의 추천 /today시간대별 메뉴 추천
[다시 추천] [정보 수정]

4.기능 명세

FR-101온보딩 화면

FR-201생년월일 입력

FR-202성별 · 양력/음력 선택

FR-203태어난 시간 선택

FR-204제출 및 저장

FR-301시간대 탭 및 접근 정책

접속 시각초기 탭차단 탭 (토스트 문구)
00:00 – 04:59저녁아침 · 점심 — "오전 5시부터 확인 가능해요"
05:00 – 10:59아침없음 (전체 열람 가능)
11:00 – 16:59점심아침 — "내일 오전 5시부터 확인 가능해요"
17:00 – 23:59저녁아침 · 점심 — "내일 오전 5시부터 확인 가능해요"

차단된 탭 클릭 시 화면 하단에 토스트가 2초간 노출됩니다.

FR-302내 정보 요약 카드

FR-303추천 결과 카드

FR-304다시 추천하기

FR-401PWA · 오프라인

FR-402WebView 임베드 대응

5.추천 로직 명세 (v1 엔진)

구현 위치: web/lib/recommendation.ts, 메뉴 데이터: web/lib/menu-data.ts

① 상태 추론UserData →
온도 · 무게 체질
② 시간대 필터아침/점심/저녁
후보군 추출
③ 스코어링반대 속성
보완 가점
④ 다양성 정렬연속 동일 이미지
회피

5.1 사용자 상태 추론

사용자를 온도 체질(warm/cold)과 무게 체질(light/heavy) 2개 축으로 분류합니다. 각 축은 우선순위가 있는 폴백 규칙으로 결정됩니다.

우선순위규칙
온도 (temperature)1출생 시각 있음: 21:00~05:59 출생 → cold, 그 외 → warm
2시간 모름: 생월 12 · 1 · 2월 → cold, 그 외 → warm
3생년월일 파싱 실패: 음력 → cold, 양력 → warm
무게 (weight)1생일 일자 1~15일 → light, 16일 이후 → heavy
2생년월일 파싱 실패: 여성 → light, 남성 → heavy

5.2 시간대 판정

현재 시각시간대
~ 10:59morning
11:00 ~ 16:59lunch
17:00 ~dinner

5.3 스코어링 및 정렬

"부족한 기운을 반대 속성 음식으로 보완한다"는 컨셉으로, 사용자 체질의 반대 속성을 가진 메뉴에 가점을 부여합니다.

5.4 이미지 다양성 재정렬

5.5 메뉴 데이터베이스

6.데이터 명세

6.1 UserData (localStorage: energy-meal:user-data)

필드타입예시설명
birthDatestring"19960822"생년월일 8자리
birthTimestring | null"07:00"십이시 구간의 시작 시각. 모름이면 null
unknownBirthTimebooleanfalse태어난 시간 모름 여부
gender"여성" | "남성""여성"성별
calendarType"양력" | "음력""양력"입력한 생년월일의 달력 기준

저장값 파싱에 실패하면 해당 키를 삭제하고 미입력 상태로 처리합니다. 저장소 접근은 반드시 lib/storage.ts 추상화를 경유합니다(PROJECT_RULES).

6.2 MenuRecommendation

필드타입설명
idstring고유 식별자 (예: lunch-poke)
namestring메뉴명 (예: 연어 포케)
descriptionstring카드 노출용 한 줄 설명
baseMenustring메뉴 계열 (예: 포케, 국밥, 죽)
temperature"warm" | "cold"음식 온도 속성
weight"light" | "heavy"음식 무게 속성
timeTimeSlot[]노출 시간대
imageKeyMenuImageKey결과 이미지 · 팔레트 · 이유 문구 매핑 키 (14종)

7.테스트 현황

계층도구대상
단위Vitest추천 로직 10케이스 — 시간대 판정 경계, 상태 추론, 반대 속성 우선 정렬, 랜덤 허용치, 이미지 다양성 · 폴백, 메뉴 데이터 규모 회귀
단위Vitest임베디드 WebView 감지 로직
컴포넌트React Testing Library온보딩 카드 · 입력 폼(검증/프리필) · 오늘의 추천 화면
E2EPlaywright온보딩 → 입력 → 결과 열람 전체 흐름
커밋 훅Husky + lint-staged변경 파일 ESLint 자동 수정 + 관련 Vitest 실행

8.알려진 한계 및 v2 개선 방향

v1 추천 엔진은 빠른 출시를 위해 사주 컨셉만 차용한 간이 규칙으로 구현되었습니다. 아래 한계가 기능명세서 v2 (고도화)의 배경입니다.

ID한계상세v2 개선
L-1 사주 요소 부재 천간지지 · 오행 등 실제 사주 계산 없이 출생 시각 · 생월 · 생일 일자의 숫자 규칙으로만 체질을 추론 만세력 기반 사주팔자 · 오행 분석 엔진 도입
L-2 음력 미변환 양력/음력을 입력받지만 실제 변환 없이 폴백 분기에만 사용 음력 → 양력 변환 후 사주 계산에 반영
L-3 낮은 개인화 사용자 상태가 온도 × 무게 = 4가지뿐이라 같은 체질이면 사실상 동일한 추천 리스트를 수신 팔자 조합 기반으로 사용자별 오행 분포 차별화
L-4 날짜 무관 추천 추천이 날짜와 무관해 "내일은 또 다른 기운이 찾아올 거예요" 문구와 실제 동작이 불일치 오늘의 일진(日辰)을 결합해 매일 달라지는 추천 구현
L-5 고정 추천 이유 추천 이유가 이미지 키별 고정 문구로, 사용자 개인의 근거를 제시하지 못함 일간 · 부족 오행 · 일진 기반의 동적 사주 풀이 노출