v2까지의 Energy Meal은 사주(오행) 기반 식사 추천에 집중했습니다. v3는 저녁 추천을 받은 사용자가 "오늘 한잔" 상황일 때, 마실 술을 고르면 사주 개인화를 유지한 채 어울리는 안주를 추천하는 안주 모드를 추가합니다. 기존 오행 스코어링 위에 술↔안주 궁합 축을 결합하는 확장이며, 식사 추천 엔진 자체는 건드리지 않습니다.
| 항목 | 확정 결정 |
|---|---|
| 진입 | /today 결과 화면에서 "오늘 한잔?" 버튼으로 안주 모드 전환 — 모든 끼니 탭에 상시 노출(v3.0.1, 당초 저녁 한정). 홈 별도 진입점은 v3.1 후보 |
| 술 분류 | 대분류 6종 — 소주 / 맥주 / 와인 / 막걸리·전통주 / 위스키·하이볼 / 사케 |
| 로직 | 사주 결합형 — 기존 오행 스코어링 유지 + 술↔안주 궁합 계열 가점 +4 |
| 데이터 | 기존 282종 중 안주 적합 메뉴 태깅 + 빈 카테고리 신규 20~30종 (안주 전용은 일반 추천에 미노출) |
| 파운데이션 | 안주 모드는 나이트 팔레트(coal 배경 + amber 액센트)로 식사 모드(cream/terra)와 시각적으로 구분. §7 참조 |
| 화면 (.pen 프레임) | 구성 |
|---|---|
| 05 오늘의 추천 · 안주 진입 | 기존 결과 화면 하단에 안주 모드 진입 배너 추가 — 모든 끼니 탭에 상시 노출(v3.0.1). 배너는 나이트 톤으로 모드 전환을 예고 |
| 06 술 선택 | 나이트 팔레트 전환. 술 6종을 2×3 카드 그리드로 노출, 단일 선택 후 CTA로 진행 |
| 07 안주 추천 결과 | 상단 술 바(선택한 술 + 술 바꾸기) + 기존 결과 카드 레이아웃 재사용(포차/바 씬 이미지) + 페어링 코멘트 + 푸터 복귀 링크 |
| 08 · 09 웹 404 (데이 · 나이트) | 플로우 밖의 화면 — 사라진 주소로 들어왔을 때. 아이콘 원 + 404 + 끊긴 경로 칩 + 오늘의 추천 보기 / 이전으로 + 빠른 이동 칩 3종 (FR-609) |
| 10 · 11 웹 오프라인 (데이 · 나이트) | 서비스워커 폴백(/offline). 404와 같은 뼈대에 오프라인 상태 칩 · 다시 시도 / 홈으로 · 점검 칩 3종 · 자동 복구 안내 (FR-609) |
| 12 · 13 앱 오프라인 (데이 · 나이트) | 앱 셸이 웹뷰 내장 에러 페이지 대신 띄우는 화면. 웹 오프라인과 같은 구성이되 브라우저 바가 없고, 연결되면 자동으로 다시 불러온다는 안내를 둠 (FR-610) |
안주 결과에서 나가는 동선은 3종입니다.
FR-601안주 모드 진입UserData)에는 아무것도 기록하지 않습니다.FR-602술 선택FR-603안주 후보 구성time: [] 방식(별도 플래그 없음, 기존 시간대 필터가 자연 제외. §6 참조).FR-604안주 스코어링baseMenu 매칭)에 +4 가점을 부여하고, 기존 오행 가점(부족 오행 +5 · 일진 상생 +2 · 랜덤 10% +1)을 유지합니다. 상세는 §5.FR-605페어링 코멘트FR-606안주 추천 결과 화면FR-607나이트 모드 전환FR-608데이터 · 이미지 확장MENU_PAIRINGS 맵).scripts/build-menu-image-map.mjs). 씬 스타일에 포차 · 호프 · 이자카야 · 전집 · 위스키/와인바 씬을 추가.아래 두 건은 안주 페어링이 아니라 셸 · 신뢰성 영역입니다. v1 FR-401(PWA · 오프라인) · FR-402(WebView 임베드)의 후속으로, 문서 관행에 따라 현행 명세인 이곳에 기록합니다.
FR-609404 · 오프라인 화면app/not-found.tsx)을 보여줍니다 — 아이콘 원 · 404 · 끊긴 경로 칩(현재 pathname) · 오늘의 추천 보기 / 이전으로 · 빠른 이동 칩 3종(오늘의 추천 · 정보 입력 · 안주 추천). 끊긴 경로는 마운트 뒤 window.location.pathname 으로 읽습니다 — usePathname 은 프리렌더 시 /_not-found 를 줘서 매 방문마다 하이드레이션 불일치(React #418)가 났습니다(v3.1.2). 이전으로는 히스토리가 없으면(외부 링크 · 알림 · 새 탭) /today 로 보냅니다./offline)은 같은 디자인 언어로 개편했습니다 — 아이콘 원 · 오프라인 상태 칩 · 다시 시도 / 홈으로 · 점검 칩 3종(Wi-Fi · 모바일 데이터 · 비행기 모드) · 자동 복구 안내. 브라우저 online 이벤트를 받으면 현재 주소를 다시 불러옵니다 — 이 화면은 원래 가려던 주소(알림 딥링크 등) 위에 서비스워커가 덮어씌운 것이라, / 로 보내면 그 목적지를 잃습니다(v3.1.2).prefers-color-scheme: dark에서 나이트 팔레트(§7)로 넘어갑니다. 공통 조각은 components/status-screen.tsx(쉘 · 아이콘 원 · 칩 · 구분선 + 인라인 SVG 아이콘)에 모았습니다./_next/ 청크를 받을 수 없습니다 — 클라이언트 컴포넌트로 두면 하이드레이션이 붙지 않아 버튼이 죽은 장식이 됩니다. 동작에 필요한 최소한(다시 시도 · 복구 시 자동 복귀)만 인라인 스크립트로 싣고, 홈으로는 SSR 에서 평범한 <a href> 로 나오는 링크라 스크립트가 통째로 실패해도 눌립니다. 서비스워커는 내용 해시가 붙은 빌드 자산(/_next/static/)을 받는 대로 쟁여 두어, 캐시된 /offline 이 CSS 없이 맨 HTML 로 뜨지 않게 합니다(v3.1.2 — 이전엔 폴백 분기만 있고 쟁이는 곳이 없어 죽은 코드였습니다). precache 는 /offline 만 필수이고 아이콘류가 실패해도 설치를 막지 않습니다.public/sw.js는 /offline을 APP_SHELL로 precache합니다. 이 페이지를 고쳤으면 CACHE_NAME(energy-meal-vN)도 반드시 함께 올려야 합니다 — sw.js가 한 바이트도 바뀌지 않으면 브라우저는 갱신을 시도조차 하지 않아 옛 화면이 계속 나옵니다(v3.1.0 배포 직후 실제로 발생, v3.1.1에서 v3 → v4). 갱신은 온라인에서 완전히 로드된 뒤 적용되므로, 검증은 ① 온라인 완전 로드 → ② 앱 완전 종료 → ③ 오프라인 전환 순서로 합니다.design/energy-meal.pen 「웹 404 · 데이/나이트」 · 「웹 오프라인 · 데이/나이트」.FR-610앱 웹뷰 오프라인 복구renderError로 이를 막고 그 자리에 오프라인 화면(components/offline-state.tsx)을 그립니다.reload(), 홈으로 = 웹뷰 재마운트 후 시작 주소로 복귀입니다. 에러 상태에서도 웹뷰를 걷지 않아 복구 시 히스토리를 잃지 않습니다.HEAD 요청을 보내고(타임아웃 4초), 응답이 오면 자동으로 reload() 합니다. 포그라운드 복귀(AppState active)에는 주기를 기다리지 않고 즉시 확인합니다. 응답 코드는 보지 않습니다 — 서버에 닿았다는 것 자체가 연결이 돌아온 신호입니다.
@react-native-community/netinfo)를 쓰면 복구를 더 빨리 잡지만 네이티브 모듈이라 APK 재빌드가 필요해, 재빌드 없이 가는 쪽을 택했습니다(사용자 결정).react-native-svg가 없어 .pen에서 PNG로 뽑아 app/assets/offline/에 두고, 작은 칩 아이콘은 단색 실루엣 + tintColor로 테마 색을 입힙니다.tone 값으로 함께 갖춰 두어, 안주 모드처럼 어두운 화면에서 끊겼을 때 바로 쓸 수 있습니다./offline(FR-609)을 먼저 내줘 이 화면과 probe 가 영영 안 탑니다 — v3.1.0~v3.1.1 에서 "잘 된다"고 확인한 앱 오프라인 화면은 실은 그 웹 화면이었고, 진짜 renderError 경로는 검증되지 않은 채였습니다. 그 경로의 결함도 같이 고쳤습니다: renderError 가 돌려준 뷰는 웹뷰 위에 덮이는 게 아니라 형제로 나란히 붙어서, flex: 1 만으로는 화면이 반으로 갈리고 위 절반에 크로미움 내장 에러 페이지가 남았습니다 → 절대 위치로 꽉 채웁니다. 이전 버전이 등록해 둔 sw 는 다음 온라인 로드 때 걷어냅니다. 검증은 앱 데이터 삭제 후 오프라인 첫 실행으로 합니다 — 온라인으로 한 번이라도 뜬 뒤라면 (구버전에선) sw 가 가로채 이 화면을 볼 수 없었습니다.loadStart를 한 번 더 쏘는데, 그 핸들러가 hasError를 풀어 probe 가 무장되자마자 해제됐습니다(logcat: error → effect armed → loadStart, 이후 probe 시작 로그 없음). 에러는 성공한 로드에서만 오는 onLoad에서 풀도록 바꿨고, 에뮬레이터에서 오프라인 → 네트워크 복구 → 자동 재로드를 확인했습니다.FR-611앱 스플래시 · 첫 화면 전환splash-blank.png)로 바꿔 크림 배경(#f6efe5)만 보이게 하고, 오버레이의 로고 + 타이틀이 그 위로 페이드로 떠오르게 했습니다 — 튈 것이 없습니다. 오버레이 덩어리는 화면 중앙입니다.preventAutoHideAsync()로 네이티브를 붙잡아 뒀다가 오버레이의 첫 onLayout에서 내립니다(fade 300ms). 자동 숨김을 막았으므로 hideAsync는 onLayout · 로드 완료 · 로드 실패 · 최후 안전장치 네 곳에서 부릅니다.onLoadEnd는 HTML을 받은 시점일 뿐이라 그때 걷으면 빈 화면이 비칩니다 — 첫 화면을 클라이언트에서 그리고 /에서 /today로 갈아타기 때문입니다. 웹이 <main>에 실제 콘텐츠를 넣으면 painted 신호를 보내고(config/webview-bridge.ts, 안 오면 1.2초 백업), 그 신호에 맞춰 450ms 페이드로 걷어 웹의 진입 애니메이션(0.45초)과 겹칩니다.FR-612웹 화면 셸 — 가운데 열 · 문서 스크롤components/app-shell.tsx 위에 놓입니다 — 열 폭 --shell-width(globals.css)를 가운데 두고 문서 자체가 스크롤합니다(vidding-re 와 같은 방식). 브라우저 스크롤바가 돌아오고 휠이 어디서든 먹습니다. 열 좌우 경계선은 마우스가 있는 기기에서만(pointer: fine) 긋고, 태블릿 · 펼친 폴드에서는 선 없이 가운데 정렬만 합니다.@media (pointer: coarse) 하나(globals.css, 터치 기기에서 --shell-width 를 none 으로) — 기기 목록을 들고 있지 않으므로 폴드 6/7/8 · 폴드형 아이패드처럼 새 기기가 나와도 손댈 것이 없습니다. 폴드는 접힌 커버(≈384px)에서 전폭, 펼치면(≈750~790px) 그 폭을 그대로 채우고, 접고 펼치는 순간 다시 흐릅니다(높이 고정 없음, min-h-dvh). 앱 웹뷰는 종전대로 폭 제한 없음.max-h-[60dvh])로 누르고 가운데를 잘라 보입니다(object-cover). 크로미움 실측: 폴드6 펼침 750×884 → 열 750, 카드 684×530 · 폴드7 펼침 790×890 → 열 790 · 아이패드 11 세로 820×1180 → 열 820, 카드 754×708 · 아이패드 가로 1180×820 → 열 1180, 카드 1114×492 · 폴드 커버 384 → 전폭 · 노트북 1280×720 · 데스크톱 1440×900 → 열 430(마우스). v3.1.5 의 폰 화면 통째 확대(zoom, min(폭/430, 높이/600)≤1.5)는 데스크톱에서 너무 커 보기 힘들어 같은 날 걷어냈습니다 — 그때 넣은 배율 스크립트 · suppressHydrationWarning 도 함께 제거.| 술 | 오행(안) | 궁합 계열 (+4 가점 대상) |
|---|---|---|
| 소주 | 수 (水) | 탕, 전골, 찌개, 회, 볶음, 무침, 조림 |
| 맥주 | 수 (水) | 튀김, 치킨, 피자, 멕시칸, 분식 |
| 와인 | 목 (木) | 파스타, 스테이크, 샐러드, 리조또, 마른안주(치즈) |
| 막걸리 · 전통주 | 토 (土) | 전, 수육(보쌈 · 족발), 안주(두부김치) |
| 위스키 · 하이볼 | 화 (火) | 마른안주, 훈제, 꼬치, 스테이크, 구이 |
| 사케 | 금 (金) | 회, 초밥, 탕, 전골, 꼬치(이자카야류) |
baseMenu(계열) 값과 매칭합니다.안주 후보(FR-603) 각 메뉴에 아래 가점을 합산해 정렬합니다. 동점은 궁합 매칭 → 부족 오행 매칭 → 원본 순서로 정렬합니다.
| 가점 | 조건 | 비고 |
|---|---|---|
| +4 | 메뉴 계열이 선택한 술의 궁합 계열과 일치 | 페어링 주축 (신규) |
| +5 | 메뉴 오행이 나의 부족 오행과 일치 | 기존 유지 — 사주 개인화 유지의 핵심 |
| +2 | 메뉴 오행이 오늘의 일진이 생(生)하는 오행 | 기존 유지 |
| +1 (10% 확률) | 랜덤 허용치 | 기존 유지 — 탐색 다양성 장치 |
getAnjuRecommendation, lib/recommendation.ts).
| 대상 | 변경 | 내용 |
|---|---|---|
MenuSeed |
필드 추가 (확정) | pairings: DrinkId[] — 신규 안주 메뉴는 시드 10번째 옵션 필드로, 기존 282종 태깅은
MENU_PAIRINGS 맵(menu-data.ts, 검수표 겸용 78종)으로 관리하고 빌드 시 병합.
빈 배열 = 안주 아님. 기존 필드는 변경 없음 |
| 안주 전용 메뉴 | 정책 확정 | time: []으로 비워 일반 추천에서 제외 — 별도 anjuOnly 플래그 없이
기존 시간대 필터가 자연 제외. 단위 테스트로 미섞임 보장 |
| 술 프로파일 | 신규 (확정) | 술 6종의 오행 · 궁합 계열 · 코멘트 문구 정의 — lib/anju.ts DRINKS |
UserData (localStorage) |
변경 없음 | 안주 모드는 화면 상태로만 존재 — 기존 사용자 마이그레이션 불필요 |
식사 모드(cream 배경 + terra 액센트)와 안주 모드를 시각적으로 구분하는 전용 팔레트입니다.
배경은 coal 그라데이션(coal-800 → coal-900), 액센트는 amber 계열을 사용하고,
CTA는 amber 배경 위 다크 텍스트(night-on-accent)로 대비를 확보합니다.
토큰은 design/energy-meal.pen의 DS / Colors NIGHT 섹션에 등록되어 있습니다.
| 토큰 | 값 | 용도 |
|---|---|---|
coal-800 | #2B211B | 나이트 배경 그라데이션 시작 |
coal-900 | #191310 | 나이트 배경 그라데이션 끝 |
amber-300 | #E8B36B | 액센트 밝은 단계 (하이라이트) |
amber-400 = night-accent | #DDA054 | 주 액센트 · CTA 배경 |
amber-500 | #C98A3E | 액센트 어두운 단계 (hover 등) |
night-on-accent | #2B1A0A | amber 배경 위 텍스트 |
night-ink | → cream-100 (#F5EFE6) | 본문 텍스트 |
night-text-secondary | #C7BCAF | 보조 텍스트 |
night-text-muted | #94897C | 낮은 위계 텍스트 |
night-text-faint | #786F64 | 희미한 텍스트 · 캡션 |
night-surface | #FFFFFF12 | 카드 · 서피스 (백색 7% 오버레이) |
night-surface-strong | #FFFFFF1F | 강조 서피스 — 칩 등 (백색 12% 오버레이) |
night-line | #FFFFFF1A | 구분선 · 보더 (백색 10% 오버레이) |
night-line-accent | #DDA05440 | 액센트 보더 — 아웃라인 버튼 등 (amber 25% 오버레이) |
나이트 모드 전용 재사용 컴포넌트 4종입니다. design/energy-meal.pen의
DS / Components · Night 프레임에 등록되어 있으며(기존 DS / Components와 별도 프레임),
06 · 07 화면의 CTA · 뱃지 · 칩 · 소형 버튼은 모두 이 컴포넌트의 인스턴스입니다.
구현 시 기존 컴포넌트의 나이트 변형(variant)으로 이식합니다.
| 컴포넌트 | 스타일 | 용도 (예시) |
|---|---|---|
| Button/Primary · Night | night-accent(amber-400) 배경 + night-on-accent 세미볼드 16px 라벨, 풀 라운드(999). amber 글로우 섀도(#DDA05433, y 14 · blur 28) |
주 CTA ("안주 추천 받기") |
| Button/Outline · sm · Night | night-line-accent 1px 보더 + night-accent 볼드 10px 라벨, radius-sm(8) |
소형 보조 액션 ("술 바꾸기") |
| Badge/Overline · Night | night-surface 배경 + night-accent 볼드 10px 영문 라벨(Inter, 자간 1.8), 풀 라운드 |
섹션 오버라인 ("TONIGHT'S PAIRING") |
| Badge/Chip · Night | night-surface-strong 배경 + #D8CFC3 볼드 11px 라벨, 풀 라운드 |
정보 칩 ("부족 기운 · 수(水)") |
| 단계 | 작업 | 산출물 |
|---|---|---|
| Step 1 | 술 프로파일 정의 + 기존 282종 안주 태깅 + 안주 전용 처리 방식 확정 | menu-data.ts 페어링 필드 + 술 프로파일 모듈 + 태깅 검수표 |
| Step 2 | 안주 스코어링 구현 (궁합 +4 결합, 온도/무게 가점 제외 여부 확정) | 추천 엔진 확장 + 단위 테스트 |
| Step 3 | UI 3장면 구현 + 나이트 토큰 · 컴포넌트 변형 이식 | 진입 배너 · 술 선택 · 안주 결과 화면 + 나이트 팔레트 CSS 토큰 + 나이트 컴포넌트 변형 4종(§7.1) |
| Step 4 | 신규 안주 메뉴 20~30종 + 포차/바 씬 이미지 생성 | 신규 시드 + webp 에셋 (v2.1 파이프라인 재사용) |
| Step 5 | 테스트 정비 · E2E 추가 · 문서 As-Built 반영 | 전체 테스트 그린 + 기능명세서 v3 확정판 |
time: [] 방식 — 별도 플래그 없음 (§6).
| 계층 | 내용 |
|---|---|
| 단위 | 궁합 계열 가점(술 6종 × 대표 계열) · 안주 후보 필터링(태깅 유무) · 안주 전용 메뉴의 일반 추천 제외 · 스코어링 정렬 |
| 컴포넌트 | 진입 배너 dinner에서만 노출 · 술 선택 상태(선택 전 CTA 비활성) · 술 배지 · 페어링 코멘트 렌더링 |
| E2E | 저녁 결과 → 안주 진입 → 술 선택 → 안주 결과 → (술 바꾸기 / 다른 안주 보기 / 식사 추천 복귀) 전체 동선 |
| 회귀 유지 | 기존 식사 추천 결과가 v3 변경 전후 동일함을 보장 (안주 전용 메뉴 미섞임 · v2 스코어링 불변) · v2 golden test 유지 |
| 버전 | 일자 | 내용 |
|---|---|---|
| v3.0 Draft | 2026-07-29 | 술 · 안주 페어링 설계 — 확정 방향 4건(진입 · 술 6종 · 사주 결합 로직 · 데이터) + Pencil 3장면 디자인 + 나이트 파운데이션(토큰 · 전용 컴포넌트 4종) 반영 |
| v3.0 | 2026-07-29 | As-Built — 구현 완료. 확정 3건(심야 = 저녁 탭 기준 노출 · 온도/무게 가점 제외 · time: []) 반영,
기존 78종 태깅 + 안주 전용 23종 · 포차/바 씬 이미지 추가, 궁합 계열 표 구현 기준 현행화,
단위 · 플로우 · E2E 테스트 추가 |
| v3.0.1 | 2026-07-30 | 진입 배너 상시 노출 — 아침 · 점심 탭에서도 안주 페어링을 미리 이용할 수 있도록 dinner 한정 노출 해제 (FR-601 개정, 사용자 결정) |
| v3.0.2 | 2026-08-14 | 셸 · 추천 UX 개정 3건 —
① 앱 설치 배너 신설 (v1 FR-401 확장): 브라우저 접속 시 하단 띠배너로 설치 유도.
크로미움은 beforeinstallprompt 네이티브 프롬프트, iOS는 공유 → 홈 화면 추가
가이드 시트. 앱 웹뷰 · standalone · 인앱 브라우저 · 7일 내 닫음은 미노출.
② 앱 웹뷰 저장 유지 수정 (v1 FR-402 개정): domStorageEnabled 활성화로
생년월일 입력이 재접속 후에도 유지.
③ 다시 추천 하루 유지 (v1 FR-304 개정): 추천 인덱스를 끼니 슬롯별로 분리해
날짜 키와 함께 localStorage에 저장 — 탭 이동 · 안주 왕복 · 재접속에도
유지되고 자정 이후 초기화 |
| v3.0.3 | 2026-08-14 | 앱 스플래시 · 로딩 화면 브랜드 통일 — 네이티브 스플래시 이미지를 로고 + 워드마크 + 태그라인 구성(.pen "00 스플래시" 시안, 배경 #F6EFE5)으로 교체하고, 웹뷰 첫 로딩 오버레이도 같은 에셋 · 배경색으로 통일해 스플래시 → 로딩이 한 화면처럼 이어지도록 개정. 앱 버전 1.0.1 |
| v3.0.4 | 2026-08-14 | 결과 화면 진입 가드 — 저장된 사용자 정보 없이 /today 에 직접
진입하면 개발용 기본 프로필(1996-08-22)로 결과를 생성해 보여주던 폴백을 제거하고
온보딩(/)으로 리다이렉트하도록 개정 |
| v3.0.5 | 2026-08-15 | 결과 화면 로딩 스켈레톤 — 저장값 확인 전 실제 값 없는 셸("-") 대신 전체 페이지 스켈레톤을 표시하도록 개정. SSR 첫 페인트와 미입력 리다이렉트의 깜빡임을 함께 해소 |
| v3.0.6 | 2026-08-15 | 끼니 간 추천 중복 제거 — 후보군이 겹치는 시간대(점심·저녁)에서 같은 날 같은 메뉴가 여러 탭에 반복 추천되지 않게 순위 라운드로빈으로 한 끼니에만 배분. 판정은 이름 기준(끼니별 변형 id 포함), 배분으로 리스트가 비면 원본 유지 |
| v3.0.7 | 2026-08-15 | 콘텐츠 확장 3차 — 메뉴 30종 · 전용 이미지 30장 추가(아침 12 · 점심 9 · 저녁 9)로 총 335종 · 이미지 299종. 기존 톤(따뜻한 원목 · 자연광 · 45도 구도)에 맞춘 개별 컷, 끼니 간 중복 제거와 함께 다시 추천 체감 리스트 확대. 이후 세션마다 50~100종씩 단계 확장 예정 |
| v3.0.8 | 2026-08-15 | 콘텐츠 확장 4차 · 이미지 배경 다변화 — 메뉴 60종 추가(아침 14 · 점심 23 · 저녁 23)로 총 395종 · 이미지 359종. "사진이 다 비슷하다"는 피드백에 따라 3 · 4차 신규 90장을 단일 원목 톤에서 요리별 장면(한옥 소반 · 다다미 · 대리석 브런치 · 트로피컬 · 홍등 중식 · 야장 포차 · 스튜디오 파스텔 등)으로 재촬영. 인물 유입 컷은 전수 검수 3회로 걸러 무인물 확인 |
| v3.0.9 | 2026-08-15 | 전 이미지 배경 다변화 완료 — 레거시 269장도 요리별 장면 뱅크(24종: 한옥 소반 · 옹기 부엌 · 야장 포차 · 숯불 · 히노키 카운터 · 홍등 중식 · 트라토리아 · 대리석 브런치 · 파스텔 스튜디오 등)로 재촬영해 전체 359장 완료. 전수 검수 에이전트 4회로 무인물 확인, 파일명 충돌 25쌍 재생성 |
| v3.0.10 | 2026-08-15 | 이미지 장면 · 각도 다변화 2차 — 배경이 여전히 비슷하다는 피드백에 따라 장면 뱅크를 48종으로 확대하고 카메라 앵글 7종(탑다운 · 아이레벨 · 3/4 · 매크로 · 히어로 · 와이드 · 사이드)을 조합해 359장 전체를 사실상 고유한 조합으로 재촬영. 장면별 사용 상한과 계열별 풀 로테이션으로 배정, 전수 검수 6회로 인물 12컷 · 깨진 글자 7컷 재생성 |
| v3.0.11 | 2026-08-16 | 콘텐츠 확장 5차 — 메뉴 80종 추가(아침 20 · 점심 30 · 저녁 30)로 총 475종 · 이미지 439장. 장면 48종 × 앵글 7종 조합 방식 유지, 전수 검수로 파일명 충돌 2쌍과 오생성 1컷 재생성 |
| v3.0.12 | 2026-08-16 | 콘텐츠 확장 6차 — 메뉴 80종 추가(아침 15 · 점심 30 · 저녁 35)로 총 555종 · 이미지 519장. 신규 이미지는 .pen 검토 프레임으로 사용자 확인 후 반영하는 절차 도입, 전수 검수로 인물 3컷 재생성 |
| v3.0.13 | 2026-08-16 | 콘텐츠 확장 7차 — 메뉴 80종 추가(아침 15 · 점심 30 · 저녁 35)로 총 635종 · 이미지 599장. .pen 검토 절차 유지, 전수 검수로 인물 2컷 · 왜곡 1컷 재생성 |
| v3.0.14 | 2026-08-16 | 콘텐츠 확장 8차 — 메뉴 70종 추가(아침 12 · 점심 28 · 저녁 30)로 총 705종 · 이미지 669장. 전수 검수로 인물 1컷 재생성 |
| v3.0.15 | 2026-08-16 | 콘텐츠 확장 9차 — 메뉴 70종 추가(아침 12 · 점심 28 · 저녁 30)로 총 775종 · 이미지 739장. 전수 검수로 인물 1컷 · 톤 이질 1컷 재생성 |
| v3.0.16 | 2026-08-16 | 콘텐츠 확장 10차 — 메뉴 75종 추가(아침 12 · 점심 30 · 저녁 33)로 총 850종 · 이미지 814장. 전수 검수 전량 통과(재생성 0) |
| v3.0.17 | 2026-08-16 | 콘텐츠 확장 11차 — 메뉴 75종 추가(아침 12 · 점심 30 · 저녁 33)로 총 925종 · 이미지 889장. 지역 별미 · 세계요리 롱테일 · 카페류 중심, 전수 검수로 4컷 재생성 |
| v3.0.18 | 2026-08-16 | 콘텐츠 확장 12차(최종) — 메뉴 75종 추가(아침 12 · 점심 30 · 저녁 33)로 목표 1,000종 달성 · 이미지 964장. 강원 별미 · 궁중요리 · 세계요리 롱테일로 마무리, 전수 검수로 2컷 재생성. 3~12차 누적 +695종 |
| v3.0.19 | 2026-08-17 | 재추천 방지 — 사용자 피드백("끼니 알림 보고 들어와도 어제와 같은 메뉴")
대응. 화면에 띄운 메뉴를 이력으로 남겨 최근 14일 내 메뉴는 감점(−100),
최근 2일 내 계열은 완화 감점(−3). 동점 정렬에 날짜 시드 랜덤
타이브레이크를 추가해 조건이 같은 날마다 같은 메뉴가 1순위로 고정되던
문제를 해소 (v2 FR-506 개정 · FR-508 신설) |
| v3.0.20 | 2026-08-19 | 메뉴 현실성 재정비 — 실사용 피드백("비현실 메뉴 때문에 오히려 안 보게 된다")에 따라 향토 · 궁중 · 초희귀 해외 요리와 아침에 안 먹는 정식류 753종을 제거해 총 247종(아침 45 · 점심 94 · 저녁 85 · 안주 23), 미사용 이미지 736장 삭제(results 67MB→16MB). 이후 추가는 사용자가 직접 골라 요청하는 방식으로 전환 |
| v3.0.21 | 2026-08-19 | 프랜차이즈 메뉴 6종 추가 — 맥모닝(아침) · 서브웨이 · 맥도날드 · 버거킹 · 롯데리아(점심) · 어묵탕(안주, 와인 제외 5종 페어링)에 피자 2종 점심 겸용 전환을 더해 총 253종(아침 46 · 점심 100 · 저녁 83 · 안주 24) · 이미지 6장 추가. 이미지는 무브랜드(로고 없는 일반 묘사)로 생성, 전수 검수로 2컷 재생성 |
| v3.0.22 | 2026-08-22 | 알림 진입 시 본 끼니 교체 — 사용자 피드백("오전에 점심 · 저녁 메뉴까지 다 봤는데
점심 알림에 같은 메뉴가 뜬다") 대응. 끼니 탭을 1.5초 이상 열어봤는지 기록해,
알림을 눌러 들어온 진입에 한해 이미 본 끼니만 다음 후보로 교체하고
"이전 메뉴 보기"로 되돌릴 수 있게 함(v2 FR-509 신설). 네이티브 셸은
알림 data.slot을 실어 /today?entry=meal-reminder&slot=…&n=…로
웹뷰를 다시 열어, 백그라운드에 살아 있던 앱도 알림 탭이 반영되게 함 |
| v3.1.0 | 2026-08-27 | 404 · 오프라인 화면 신설 (FR-609 · FR-610) — 없는 주소는 Next.js 기본 404,
앱은 웹뷰 내장 에러 페이지가 그대로 노출되던 것을 브랜드 화면으로 교체.
.pen에 6장(웹 404 · 웹 오프라인 · 앱 오프라인 × 데이/나이트)을 먼저 그리고 그대로 옮김 —
색 · 간격 · 라운드는 기존 토큰만 사용.
앱은 renderError로 내장 페이지를 막고 다시 시도 = reload / 홈으로 = 재마운트,
연결 복구는 네이티브 의존성 없이 HEAD probe(3초) + AppState 복귀로 감지해 자동 reload
(NetInfo 미도입 = APK 재빌드 없음, 사용자 결정). 웹은 prefers-color-scheme로 나이트 팔레트 대응.
디자인 문서에 시안 6장 추가 |
| v3.1.1 | 2026-08-28 | 실기 확인에서 드러난 두 건 수정 —
① 앱 스플래시(FR-611 신설): 네이티브 로고가 512px 원본을 늘린 것이라 흐릿했던 것을
1024px 원본으로 교체(imageWidth 226으로 보정해 표시 크기 유지),
preventAutoHideAsync + 오버레이 onLayout으로 이음매 정리,
최소 노출 1.8초 제거 후 웹의 painted 신호에 맞춰 450ms 페이드,
스피너는 10초 초과 시에만. 앱 v1.1.8.
② 오프라인 화면이 옛 캐시로 뜨던 문제(FR-609 개정):
sw.js를 고치지 않아 서비스워커가 갱신되지 않았던 것 — CACHE_NAME v3 → v4.
같이 드러난 문제로, 오프라인에서는 /_next/ 청크를 받을 수 없어 버튼이 죽는 상태였던 것을
서버 컴포넌트 + 인라인 스크립트로 바꿔 JS 번들 없이 동작하게 함 |
| v3.1.2 | 2026-08-29 | 다관점 재검토(102 에이전트)에서 드러난 결함 수정 —
① 앱 오프라인 실제 경로(FR-610 개정): 웹뷰 안 서비스워커가 캐시된 웹 /offline 을 먼저 내줘
네이티브 화면이 한 번도 검증되지 않았음을 확인. 그 경로는 renderError 뷰가 웹뷰의 형제로 붙어 화면이 반으로
갈리던 결함, 그리고 에러 직후 크로미움의 에러 페이지 loadStart가 hasError를 풀어 자동 복구 probe 가 한 번도 돌지 않던 결함이 있었음 → 절대 위치 · onLoad에서만 에러 해제로 수정, 웹뷰에선 sw 미등록(기존 등록분 해제).
② 네이티브 스플래시 배경 전용(FR-611 개정): 로고를 투명 PNG 로 바꿔 두 단계 사이 로고 점프 제거.
스피너 타이머를 오버레이 단위로.
③ 웹(FR-609 개정): 404 하이드레이션 불일치(#418) 수정 · 이전으로 히스토리 폴백 ·
오프라인 자동 복귀를 reload 로(딥링크 보존) · sw 해시 자산 캐시(죽은 폴백 살림) · precache 원자성 완화 ·
<a>→Link(lint).
④ 나이트 보조 텍스트 토큰 앱/웹 정합(night-muted), 문서 수치 현행화(시안 16장 · 메뉴 253 · 이미지 234). 앱 v1.1.10 |
| v3.1.3 | 2026-08-31 | 스플래시 최소 노출 1.5초 복원(FR-611 개정) — 정적 웹이 1초 안에 떠서 브랜드 화면이 읽기도 전에 사라지던
것(사용자 피드백). 첫 실행 오버레이에만 적용, 재시도 · 홈으로는 제외. 루트 문서(PROJECT_RULES · TESTING_STRATEGY ·
IMPLEMENTATION_PLAN) · web/README · spec-v2 현행 수치 현행화. 앱 v1.1.11 |
| v3.1.4 | 2026-08-31 | 웹 화면 셸 개편(FR-612 신설) — 넓은 화면의 폰 베젤(둥근 모서리 · 검은 테두리 · 820px 고정 높이)과
베젤 안 숨긴 스크롤을 걷어내고, 430px 열을 가운데 둔 채 문서 자체가 스크롤하게 함(사용자 피드백: 스크롤 여부를 알 수 없음).
6개 화면 블록을 공용 app-shell.tsx로 통합, 열 폭은 --shell-width 한 곳. 좌우 경계선은
pointer: fine 기기에서만. 화면 전환 시 스크롤 맨 위로 복귀. 앱 변경 없음(웹 전용 — 앱 v1.1.11 그대로, 재설치 불필요) |
| v3.1.5 | 2026-08-31 | 넓은 화면 배율 규칙(FR-612 개정) — v3.1.4 배포 뒤 피드백("아이패드에서 폭이 안 늘어난다", "비율만 크게",
폴드 7/8 · 폴드형 아이패드 대비). 430px 열을 가운데 두는 대신 폰 화면을 그대로 확대:
--shell-zoom = clamp(1, min(폭/430, 높이/600), 1.5)(layout.tsx 인라인 스크립트, 첫 페인트 전 · 접힘/펼침 · 회전마다),
열 폭 640(확대 좌표, 실제 최대 960px). 정사각 이미지 카드는 뷰포트 60% 높이 상한으로 가운데 크롭.
기기 매트릭스 10종 크로미움 실측. 앱 변경 없음 |
| v3.1.6 | 2026-08-31 | 넓은 화면 규칙 재정의(FR-612 개정) — v3.1.5 의 통째 확대가 데스크톱에서 너무 커 보기 힘들다는 피드백으로 같은 날 철회.
마우스로 보는 웹은 430px 열 그대로, 터치 기기(폰 · 펼친 폴드 · 아이패드)는 열이 화면 폭을 그대로 채움(글자 크기 유지) —
@media (pointer: coarse) 로 --shell-width: none. 배율 스크립트 · suppressHydrationWarning 제거,
이미지 카드 60dvh 상한은 유지. 앱 변경 없음 |
| v3.1.7 | 2026-09-08 | 알림 진입 시 본 끼니 교체(v2 FR-509) 개정 — 사용자 피드백("빠르게 슥 넘기며 보는데 알림에 이미 본 메뉴가 그대로 뜬다").
점검 결과 로직은 배포본에서 정상 동작했고, 1.5초 체류 기준이 사용 습관과 어긋난 것이 원인.
탭을 직접 누르면 즉시 · 화면을 열 때 펴진 첫 탭도 즉시 본 것으로 기록하고,
1.5초 체류 기준은 자동으로 펴진 탭(복귀 시 끼니 전환 · 자정 재구성)에만 남김.
결과 화면 첫 탭은 0~4시도 아침(당초 저녁) — 날짜 시드가 자정에 바뀌어 새 날의 메뉴가 뜨므로(사용자 결정).
앱 변경 없음(웹 전용, 앱 v1.1.11 그대로) |