Compare commits
20 Commits
v0.1.65
...
e3cbba1a49
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3cbba1a49 | ||
|
|
ce5de2e8ce | ||
|
|
e8748f3434 | ||
|
|
b259cec11b | ||
|
|
aba6fac2ae | ||
|
|
63354fa63a | ||
|
|
09ddc47103 | ||
|
|
77aad4ab14 | ||
|
|
935c73129b | ||
|
|
1815a4c4b2 | ||
|
|
c13b976ca3 | ||
|
|
e0e9ab6936 | ||
|
|
fd4ab18fbf | ||
|
|
622ea58cd1 | ||
|
|
7bf21b5b45 | ||
|
|
6754976e72 | ||
|
|
5d62866941 | ||
|
|
7639fd009d | ||
|
|
4760b5a284 | ||
|
|
2eb16ce861 |
129
CHANGELOG.md
129
CHANGELOG.md
@@ -4,8 +4,137 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-15
|
||||
|
||||
### 🚀 [Release] v0.1.67 운영 배포 — #532 / #533 / #545
|
||||
- 대상: 2026-07-27 이후 main에 누적된 15개 커밋 (v0.1.66 이후 미배포분)
|
||||
- #532 지역 표시 계층화(`한국|서울` → `한국 › 서울`), #533 언급 적은 식당 제외 필터(min_mentions), #545 해외 식당 예약버튼 숨김
|
||||
- 절차: Colima(aarch64) 빌드 → OCIR push(`icn.ocir.io/idyhsdamac8c/tasteby/{backend,frontend}:v0.1.67`) → `kubectl set image` → rollout 완료
|
||||
- 운영 검증: `min_mentions=0` → 500곳, `=3` → 36곳, `=5` → 5곳 — 서버사이드 필터 정상 동작
|
||||
- git tag `v0.1.67` 생성 및 Gitea push. Redmine #532/#533/#545 → 08-Documenter 전진
|
||||
|
||||
### 📄 [Docs] 모두의 창업 2차 지원서 작업방 신설 — `docs/ir/modu-startup-2026-09/`
|
||||
- `questions.md`(문항 원문·제약), `v1.md`(1차 지원서 원고 보존), `v2.md`(Codex 작성분 이관), `v3.md`(실측 반영), `v4.md`(Q8 완성)
|
||||
- 실측 지표 확보: 채널 6곳 / 영상 909편 / 노출 식당 500곳(좌표 100%) / 해외 60여 곳(일본 28) / LLM 미검증 1,071건
|
||||
- v3에서 로드맵 수정: "3개월 내 식당 5,000곳"(현재의 10배, 달성 불가) → 1,500곳 + 미검증 1,071건 정리를 0~3개월 과제로 재정의
|
||||
- Redmine #791 연계
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-27
|
||||
|
||||
### ✅ [Reviewer] #533 언급 적은 식당 제외 필터 — 승인 (게이트 통과)
|
||||
- 검토 대상: backend(`Restaurant.videoCount`, `RestaurantMapper` xml/iface, `RestaurantService`, `RestaurantController`), frontend(`lib/api.ts`, `lib/filters.ts`, `app/page.tsx`), `__tests__/filters.test.ts`
|
||||
- 정확성: video_count 스칼라 서브쿼리(strong/unknown)와 min_mentions 서버필터 로직 일치. DISTINCT+스칼라 서브쿼리는 r.id 단위라 결과 불변. 캐시 키에 `mm=` 포함(필터별 분리). `minMentions > 0` 가드로 음수/null 안전. `includeHidden` 오버로드 리팩터링에 유실된 호출부 없음(true 사용처 부재 확인)
|
||||
- 설계 일치: `docs/design/533-min-mentions-filter/README.md`와 구현 일치. 순수 함수 `passesMinMentions()` 분리로 경계값/null 테스트 6케이스 커버
|
||||
- 직접 수정(Reviewer): 설계 §7 "내위치 토글 ON → setMinMentions(0)" 요구 대비 데스크톱 토글만 반영되고 모바일 토글 2곳 누락 → 두 모바일 토글에 `setMinMentions(0)` 추가(반응형 리사이즈 시 일관성 확보, 통상 모바일 흐름에선 no-op). tsc/jest(6 suites, 32 tests) 통과
|
||||
- 06-Reviewer 승인 → 07-Release 대기 (배포는 Release 단계에서 수행)
|
||||
|
||||
### ✅ [Reviewer] #532 지역 표시 계층화 — 승인 (게이트 통과)
|
||||
- 검토 대상: `frontend/src/lib/region.ts`(`formatRegion`), `RestaurantDetail.tsx`/`RestaurantList.tsx`(적용·렌더 가드), `__tests__/region.test.ts`
|
||||
- 정확성: `formatRegion`은 순수 함수(I/O 없음, 단일 책임). falsy/`null` 토큰(대소문자 무시)/빈 토큰/더미 `나라`/trim/전량 더미(`""`) 모두 정상 처리 — 재실행한 단위 테스트 8/8 통과
|
||||
- 설계 일치: 구현이 `docs/design/532-region-display/README.md`와 일치. Designer 단계의 렌더 가드 변경(`region &&` → `formatRegion(region) &&`)이 설계서에 선반영됨 → 전 토큰 더미 시 빈 배지/빈 줄 미렌더 확인
|
||||
- 회귀 안전성: c13b976에서 착오로 되돌아간 #545 접근성 표시(title/aria-hidden)가 935c731로 복원됨을 확인 — 현재 파일 상태 정상
|
||||
- 범위 판단: `buildSearchQuery`(공백 조인, 외부 지도 검색)는 의도적으로 유지 — 적절. Admin 패널(UsersPanel/VideosPanel/RestaurantsPanel)의 raw region 표기는 설계서 비범위(관리자 화면)로, 이번 사용자 화면 버그와 무관 — 반려 사유 아님(후속 정리 권고)
|
||||
- 06-Reviewer 승인 → 07-Release 대기 (배포는 Release 단계에서 수행)
|
||||
|
||||
### 🛠 [Developer] #533 Reviewer 반려 수정 — "전체보기" 버튼 언급수 필터 초기화
|
||||
- 파일: `frontend/src/app/page.tsx`
|
||||
- 전역 "전체보기" 버튼 노출 조건에 `|| minMentions > 0` 추가 → 언급수 필터만 켜져 있어도 버튼 노출
|
||||
- onClick 초기화 목록에 `setMinMentions(0)` 추가 → 다른 필터와 함께 켠 상태에서도 전체 초기화됨
|
||||
- "내위치" 토글 ON 초기화 목록에도 `setMinMentions(0)` 추가(내위치 ↔ 언급수 상호배타 일관성)
|
||||
- 설계서 동기화: `docs/design/533-min-mentions-filter/README.md` §7에 "필터 리셋 일관성" 명시
|
||||
- 검증: `tsc --noEmit` 통과, jest 6 suites / 32 tests 통과. 코어 필터 로직은 이전과 동일(변경 없음)
|
||||
- 03-Developer → 06-Reviewer(재검토)
|
||||
|
||||
### 🛑 [Reviewer] #533 반려 — 전역 "전체보기" 버튼이 언급수 필터를 초기화하지 않음
|
||||
- 파일: `frontend/src/app/page.tsx:910`(노출 조건), `912-919`(onClick 초기화 목록)
|
||||
- 문제: 전역 필터 초기화 버튼("전체보기")의 노출 조건과 초기화 로직에 `minMentions`가 누락됨
|
||||
- 언급수 필터만 켜져 있으면 버튼 자체가 노출되지 않음(그룹 로컬 X 버튼으로는 초기화 가능)
|
||||
- 다른 필터와 언급수 필터를 함께 켠 상태에서 "전체보기"를 눌러도 언급수 필터는 계속 적용된 채로 남아, 사용자가 전체 초기화됐다고 오인할 수 있음
|
||||
- 권고: 910행 조건에 `|| minMentions > 0` 추가, 912-919행에 `setMinMentions(0)` 추가. "내위치" 토글 초기화 목록도 함께 점검 권고
|
||||
- 코어 필터 로직(설계서 일치, 경계값, 보안)은 문제 없음 — 이 결함만으로 반려
|
||||
- 06-Reviewer → 03-Developer 로 반려
|
||||
|
||||
### 🎨 [Designer] #533 UX 검토 — 코드 변경 없음
|
||||
- 데스크톱 툴바 "언급" 셀렉트가 기존 필터(장르/가격/나라)와 동일한 패턴(플레이스홀더/강조색/그룹 X 초기화/tooltip)을 따름을 확인, 문구 변경 불필요
|
||||
- 전역 "전체보기" 버튼 결함 발견 → 동작 변경이 필요해 Designer 범위 밖으로 판단, Reviewer 단계로 이관
|
||||
- 05-Designer → 06-Reviewer 로 전진 (코드 변경 없음)
|
||||
|
||||
### ✅ [QA] #533 언급 적은 식당 제외 필터 — 검증 통과
|
||||
- 설계서(`docs/design/533-min-mentions-filter/README.md`)와 구현(commit 7639fd0) 일치 확인
|
||||
- 백엔드: `RestaurantMapper.xml findAll` 스칼라 서브쿼리(`video_count`) + `min_mentions` 필터, `DISTINCT` 조합에도 중복 없음 확인
|
||||
- 프론트: `page.tsx` `filteredRestaurants`에서 `video_count` 가드 적용, 데스크톱 툴바 "언급" 셀렉트(2/3/5회+)
|
||||
- dev API 실측 검증: `min_mentions=0/1/2/3/5/100` 전 구간에서 경계 위반 0건 (=2→116개, =3→36개, =5→5개, =100→0개, 음수/0은 미적용과 동일)
|
||||
- `cuisine`/`channel` 등 기존 필터와 조합 시에도 회귀 없음 확인
|
||||
- 회귀 테스트 추가: `passesMinMentions()`을 `frontend/src/lib/filters.ts`로 추출(동작 변경 없음, 테스트 가능성 확보) + `frontend/__tests__/filters.test.ts`(6케이스: 미적용/음수/미만/경계값/초과/null·undefined)
|
||||
- 백엔드 빌드, `tsc --noEmit`, 프론트 전체 jest 스위트(6 suites, 32 tests) 통과
|
||||
- 갭(참고, 반려 사유 아님): `min_mentions` 필터 UI가 데스크톱 툴바에만 있고 모바일 FilterSheet에는 미적용 — 설계서에서 서버사이드 일원화(#535)로 이미 분리한 범위, 모바일 UI 적용은 #535 진행 시 함께 처리 권고
|
||||
- 04-QA → 05-Designer 로 전진
|
||||
|
||||
### 🎨 [Designer] #532 지역 표시 빈 배지 방지 — 렌더 가드 정리
|
||||
- 문제: `RestaurantList.tsx`/`RestaurantDetail.tsx`가 원본 `region` 문자열(예: `"|"`, `"한국|"`)의 truthy 여부로 표시 여부를 결정 → 전 토큰이 더미/빈 값이어서 `formatRegion()` 결과가 `""`이 되는 경우에도 빈 지역 배지/줄이 렌더되어 레이아웃에 불필요한 간격이 남을 수 있었음(dev 데이터에서는 미발견, 이론적 엣지케이스)
|
||||
- 해결: 표시 가드를 `r.region &&` → `formatRegion(r.region) &&` 로 변경(두 파일 모두). `formatRegion()` 로직/시그니처는 변경 없음 — 호출부 조건만 정리
|
||||
- `tsc --noEmit`, 프론트 전체 jest 스위트(5 suites, 26 tests) 통과
|
||||
- 05-Designer → 06-Reviewer 로 전진
|
||||
|
||||
### ✅ [QA] #545 해외 식당 예약 버튼 숨김 — 검증 통과
|
||||
- 설계서(`docs/design/545-hide-foreign-reservation-buttons/README.md`) 인수조건 대비 구현(`RestaurantDetail.tsx`) 일치 확인
|
||||
- 테이블링/캐치테이블 버튼 2곳 모두 `isKoreaRestaurant(restaurant) &&` 게이트 적용됨 (지도 링크 분기와 동일 판정 기준 재사용)
|
||||
- 회귀 테스트 추가: `frontend/__tests__/RestaurantDetail.test.tsx` (5케이스)
|
||||
- 국내 좌표(서울) → 버튼 노출, 해외 좌표(방콕, 대표 발견 케이스) → 버튼 숨김
|
||||
- 해외+URL 없음(도쿄) → 숨김 유지, 좌표 없음+region null → fallback으로 국내 간주(기존 동작 유지)
|
||||
- 예약 URL `"NONE"` 문자열 → 국내 식당이어도 버튼 없음(기존 게이트 유지, 회귀 없음)
|
||||
- `tsc --noEmit` 통과, 프론트 전체 jest 스위트(5 suites, 26 tests) 통과
|
||||
- 04-QA → 05-Designer 로 전진
|
||||
|
||||
### ✅ [QA] #532 지역 표시 계층화 — 검증 통과
|
||||
- `formatRegion()` 설계서(docs/design/532-region-display/README.md) 명세대로 구현됨을 확인
|
||||
- 단위 테스트 추가: `frontend/__tests__/region.test.ts` (falsy, 계층 조인, `null`/빈 토큰/더미 `나라` 제거, 단일 토큰, 전량 더미, trim 8케이스) — 전부 통과
|
||||
- `tsc --noEmit` 통과, 프론트 전체 jest 스위트(4 suites, 21 tests) 통과
|
||||
- 실제 dev DB 데이터(`region: "한국|서울|"` 등)로 엣지케이스 재확인 — 설계서 예시와 일치
|
||||
- 04-QA → 05-Designer 로 전진
|
||||
|
||||
## 2026-07-19
|
||||
|
||||
### 📋 설계서/Redmine 현행화 — #545/#533/#532 파이프라인 정지 점검
|
||||
- 발견: #545/#533/#532 세 이슈가 Developer 구현 완료(2026-06-28) 이후 04-QA 단계에서 3주간 정지 확인
|
||||
- #545: Architect 단계 없이 구현되어 설계서 게이트 위반 확인 → `docs/design/545-hide-foreign-reservation-buttons/README.md` 소급 작성
|
||||
- #533, #532: 기존 설계서가 실제 구현과 일치함을 재확인 (수정 없음)
|
||||
- Redmine 3건에 현재 상태 저널 노트 반영 (잔여: 육안 QA)
|
||||
- git/Redmine/설계서 3자 정합성 점검 — git 클린, 대응 커밋 확인 완료
|
||||
|
||||
## 2026-06-28
|
||||
|
||||
### 🐛 해외 식당에 테이블링/캐치테이블 예약 버튼 노출 수정 (#545)
|
||||
- 문제: 국내 전용 예약 서비스 버튼이 해외 식당 상세에도 노출 (URL만 있으면 렌더)
|
||||
- 해결: RestaurantDetail.tsx 두 예약 버튼을 `isKoreaRestaurant()`로 게이트 (지도 링크와 동일 기준)
|
||||
- 후속(옵션): 백엔드 예약 URL 검색/벌크가 해외 식당 제외
|
||||
|
||||
### ✨ 언급 적은(관련도 낮은) 식당 제외 필터 (#533)
|
||||
- 신호: "의미있는 언급 수" = video_restaurants 중 relevance ∈ (strong, unknown) 개수 (weak/incidental 제외)
|
||||
- 백엔드: 식당 목록 응답에 `video_count` 추가 + `min_mentions` 서버 필터 파라미터
|
||||
- RestaurantMapper.xml findAll: 스칼라 서브쿼리 video_count + minMentions 필터
|
||||
- Restaurant.videoCount 필드 / Service·Controller 스레드 / 캐시키 `mm=` 포함
|
||||
- 검증: min_mentions=2 → 116개(전부 ≥2, 위반 0), =3 → 36개
|
||||
- 프론트: Restaurant.video_count 타입 + 데스크톱 툴바 "언급" 필터(2/3/5회+) 클라이언트 필터
|
||||
- 후속: 모바일 FilterSheet 적용 + 서버사이드 일원화(#535)
|
||||
- 설계서: `docs/design/533-min-mentions-filter/README.md`
|
||||
|
||||
### 🐛 지역 표시 계층화 — "한국|서울" → "한국 › 서울" (#532)
|
||||
- 문제: 식당 상세/리스트가 region 원본(`한국|서울|강남구`, 파이프 노출)을 그대로 표시
|
||||
- 해결: 공용 유틸 `lib/region.ts` `formatRegion()` 신설 — 빈토큰/`null`/더미(`나라`) 제거 후 ` › ` 계층 조인
|
||||
- 적용: `RestaurantDetail.tsx`(지역 표기), `RestaurantList.tsx`(카드 지역)
|
||||
- 검색 쿼리용 `buildSearchQuery`(공백 조인)는 유지 — 외부 지도 검색 호환
|
||||
- 설계서: `docs/design/532-region-display/README.md`
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### 🎯 클러스터 expansion 후 마커 클릭 시 재묶임 방지 (v0.1.66)
|
||||
- 기존: selected 시 무조건 zoom 16 → 클러스터 expansion(18)에서 마커 클릭하면 다시 16으로 줄어 재묶임
|
||||
- 변경: 현재 zoom ≥ 16이면 유지, 미만이면 16으로 (NaverMap morph + GoogleMap setZoom 조건부)
|
||||
- page.tsx의 setRegionFlyTo 호출 제거 — selected useEffect로 일원화 (zoom 16 강제 회피)
|
||||
|
||||
### 🐛 NaverMap 클러스터 클릭 시 중앙 이동 fix (v0.1.65)
|
||||
- panTo(애니메이션) + setZoom(z, true)(애니메이션) 두 애니메이션 동시 호출이 서로 cancel
|
||||
- 단일 식당은 줌 변화 없어서 안 보였고, 클러스터는 줌 크게 변경 → 충돌 가시화
|
||||
|
||||
@@ -56,17 +56,18 @@ public class RestaurantController {
|
||||
@RequestParam(defaultValue = "0") int offset,
|
||||
@RequestParam(required = false) String cuisine,
|
||||
@RequestParam(required = false) String region,
|
||||
@RequestParam(required = false) String channel) {
|
||||
@RequestParam(required = false) String channel,
|
||||
@RequestParam(name = "min_mentions", required = false) Integer minMentions) {
|
||||
if (limit > 500) limit = 500;
|
||||
String key = cache.makeKey("restaurants", "l=" + limit, "o=" + offset,
|
||||
"c=" + cuisine, "r=" + region, "ch=" + channel);
|
||||
"c=" + cuisine, "r=" + region, "ch=" + channel, "mm=" + minMentions);
|
||||
String cached = cache.getRaw(key);
|
||||
if (cached != null) {
|
||||
try {
|
||||
return objectMapper.readValue(cached, new TypeReference<List<Restaurant>>() {});
|
||||
} catch (Exception e) { log.warn("Cache deserialize failed, evicting: {}", e.getMessage()); cache.del(key); }
|
||||
}
|
||||
var result = restaurantService.findAll(limit, offset, cuisine, region, channel);
|
||||
var result = restaurantService.findAll(limit, offset, cuisine, region, channel, minMentions, false);
|
||||
cache.set(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -39,4 +39,7 @@ public class Restaurant {
|
||||
// Transient enrichment fields
|
||||
private List<String> channels;
|
||||
private List<String> foodsMentioned;
|
||||
|
||||
// #533 — 의미있는(strong/unknown) 영상 언급 수
|
||||
private Integer videoCount;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public interface RestaurantMapper {
|
||||
@Param("cuisine") String cuisine,
|
||||
@Param("region") String region,
|
||||
@Param("channel") String channel,
|
||||
@Param("minMentions") Integer minMentions,
|
||||
@Param("includeHidden") boolean includeHidden);
|
||||
|
||||
// #322 LLM 검증: hidden 표시 갱신
|
||||
|
||||
@@ -21,11 +21,13 @@ public class RestaurantService {
|
||||
}
|
||||
|
||||
public List<Restaurant> findAll(int limit, int offset, String cuisine, String region, String channel) {
|
||||
return findAll(limit, offset, cuisine, region, channel, false);
|
||||
return findAll(limit, offset, cuisine, region, channel, null, false);
|
||||
}
|
||||
|
||||
public List<Restaurant> findAll(int limit, int offset, String cuisine, String region, String channel, boolean includeHidden) {
|
||||
List<Restaurant> restaurants = mapper.findAll(limit, offset, cuisine, region, channel, includeHidden);
|
||||
// #533 — minMentions: 의미있는 언급 수가 N 미만인 식당 제외 (null/0이면 미적용)
|
||||
public List<Restaurant> findAll(int limit, int offset, String cuisine, String region, String channel,
|
||||
Integer minMentions, boolean includeHidden) {
|
||||
List<Restaurant> restaurants = mapper.findAll(limit, offset, cuisine, region, channel, minMentions, includeHidden);
|
||||
enrichRestaurants(restaurants);
|
||||
return restaurants;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<result property="hidden" column="hidden" javaType="java.lang.Boolean"/>
|
||||
<result property="hiddenReason" column="hidden_reason"/>
|
||||
<result property="verifiedAt" column="verified_at"/>
|
||||
<result property="videoCount" column="video_count"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- ===== Queries ===== -->
|
||||
@@ -33,7 +34,9 @@
|
||||
SELECT DISTINCT r.id, r.name, r.address, r.region, r.latitude, r.longitude,
|
||||
r.cuisine_type, r.price_range, r.google_place_id, r.tabling_url, r.catchtable_url,
|
||||
r.business_status, r.rating, r.rating_count, r.updated_at,
|
||||
r.hidden, r.hidden_reason, r.verified_at
|
||||
r.hidden, r.hidden_reason, r.verified_at,
|
||||
(SELECT COUNT(*) FROM video_restaurants vrc
|
||||
WHERE vrc.restaurant_id = r.id AND vrc.relevance IN ('strong','unknown')) AS video_count
|
||||
FROM restaurants r
|
||||
<if test="channel != null and channel != ''">
|
||||
JOIN video_restaurants vr_f ON vr_f.restaurant_id = r.id
|
||||
@@ -55,6 +58,10 @@
|
||||
<if test="channel != null and channel != ''">
|
||||
AND c_f.channel_name = #{channel}
|
||||
</if>
|
||||
<if test="minMentions != null and minMentions > 0">
|
||||
AND (SELECT COUNT(*) FROM video_restaurants vrc
|
||||
WHERE vrc.restaurant_id = r.id AND vrc.relevance IN ('strong','unknown')) >= #{minMentions}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY r.updated_at DESC
|
||||
OFFSET #{offset} ROWS FETCH NEXT #{limit} ROWS ONLY
|
||||
|
||||
46
docs/design/532-region-display/README.md
Normal file
46
docs/design/532-region-display/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# #532 — 지역 표시 계층화 (formatRegion)
|
||||
|
||||
## 배경 / 문제
|
||||
지역(`region`)은 `나라|시도|구군` 파이프 구분 문자열(예: `한국|서울|강남구`).
|
||||
사용자 화면에 **원본이 그대로 노출**되어 `한국|서울|강남구`(파이프) 또는 평문 `한국 서울`로 보임.
|
||||
기대: **`한국 › 서울 › 구군`** 계층(breadcrumb) 표시.
|
||||
|
||||
## 범위
|
||||
- 식당 상세 시트의 "지역" 표기 (`RestaurantDetail.tsx`)
|
||||
- 식당 리스트 카드의 지역 표기 (`RestaurantList.tsx`)
|
||||
- 공용 유틸 `formatRegion()` 신설 (`lib/region.ts`)
|
||||
|
||||
비범위: 지역 *필터* 동작/정렬(정상), 외부 지도 검색 쿼리(`buildSearchQuery` — 공백 조인 유지), 데이터 정합성(별도 이슈).
|
||||
|
||||
## 함수 설계
|
||||
|
||||
### `formatRegion(region: string | null | undefined): string`
|
||||
- **입력**: 파이프 구분 지역 문자열 (예: `"한국|서울|강남구"`, `"일본|null"`, `"한국||관악구"`, `""`)
|
||||
- **처리**:
|
||||
1. falsy → `""` 반환
|
||||
2. `split("|")` → 각 토큰 `trim()`
|
||||
3. 빈 토큰, `"null"`(대소문자 무시), 더미 `"나라"` 제거
|
||||
4. 남은 토큰을 `" › "`(U+203A)로 조인
|
||||
- **출력 예**:
|
||||
| 입력 | 출력 |
|
||||
|---|---|
|
||||
| `한국\|서울\|강남구` | `한국 › 서울 › 강남구` |
|
||||
| `일본\|null` | `일본` |
|
||||
| `한국\|\|관악구` | `한국 › 관악구` |
|
||||
| `""` / `null` | `""` (호출부에서 미표시) |
|
||||
- **순수 함수**(I/O 없음) → 단위 테스트 용이.
|
||||
|
||||
### 적용
|
||||
- `RestaurantDetail.tsx:132`: `{restaurant.region}` → `{formatRegion(restaurant.region)}`
|
||||
- `RestaurantList.tsx:54`: `{r.region}` → `{formatRegion(r.region)}`
|
||||
- 표시 가드: 원본 `region &&`(truthy) 가 아니라 `formatRegion(region) &&`(변환 결과 truthy) 로 감싼다.
|
||||
원본이 `"|"`/`"한국|"`처럼 전 토큰 더미인 경우 원본은 truthy 여도 변환 결과는 `""` 이므로,
|
||||
가드를 원본 기준으로 두면 빈 배지/빈 줄이 렌더된다(#532 Designer 단계에서 발견·수정).
|
||||
|
||||
## 엣지케이스
|
||||
- 모든 토큰이 더미/빈 값(`"한국|"`, `"|"`) → 유효 토큰만 남김(`한국`) 또는 `""`. `formatRegion(region) &&` 가드로 `""`이면 미표시.
|
||||
- 단일 토큰(`"한국"`) → `한국` 그대로.
|
||||
|
||||
## 검증
|
||||
- 단위 테스트(가능 시) 또는 dev 화면에서 상세/리스트 지역 표기가 `›` 계층으로 보이는지.
|
||||
- `npm run build`(또는 tsc/lint) 통과.
|
||||
48
docs/design/533-min-mentions-filter/README.md
Normal file
48
docs/design/533-min-mentions-filter/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# #533 — 언급 적은(관련도 낮은) 식당 제외 필터
|
||||
|
||||
## 배경 / 문제
|
||||
영상에서 잠깐·우연히 언급된(=관련도 낮은) 식당까지 모두 노출되어 신호 대비 잡음이 큼.
|
||||
사용자가 "언급이 충분한 식당만" 보도록 제외 필터 제공.
|
||||
|
||||
## 신호 정의
|
||||
"의미있는 언급 수(`video_count`)" = 해당 식당의 `video_restaurants` 링크 중
|
||||
**relevance ∈ ('strong','unknown')** 개수. (weak/incidental = 곁다리 언급 → 제외)
|
||||
→ 기존 `findVideoLinks` 기본 노출 정책(strong/unknown)과 일관.
|
||||
|
||||
## 범위
|
||||
- **백엔드**: 식당 목록 응답에 `video_count` 포함 + `min_mentions` 서버 필터 파라미터.
|
||||
- **프론트**: `Restaurant.video_count` 타입 + 클라이언트 필터 UI(전체/2회+/3회+).
|
||||
- 서버사이드 필터 일원화(현 클라 필터 패턴 통일)는 **#535**로 분리.
|
||||
|
||||
## 함수/변경 설계
|
||||
|
||||
### 백엔드
|
||||
1. `domain/Restaurant.java` — `Integer videoCount` 필드 추가(전이 enrichment).
|
||||
2. `mapper/RestaurantMapper.xml`
|
||||
- `restaurantMap` resultMap: `<result property="videoCount" column="video_count"/>`
|
||||
- `findAll` SELECT에 스칼라 서브쿼리 추가:
|
||||
`(SELECT COUNT(*) FROM video_restaurants vrc WHERE vrc.restaurant_id = r.id AND vrc.relevance IN ('strong','unknown')) AS video_count`
|
||||
- `findAll` `<where>`에 optional 필터:
|
||||
`<if test="minMentions != null and minMentions > 0"> AND (위 서브쿼리) >= #{minMentions} </if>`
|
||||
3. `mapper/RestaurantMapper.java` — `@Param("minMentions") Integer minMentions` 추가.
|
||||
4. `service/RestaurantService.java` — `findAll(..., Integer minMentions, boolean includeHidden)`로 스레드. 5-arg 오버로드는 `null, false` 전달.
|
||||
5. `controller/RestaurantController.java` — `@RequestParam("min_mentions") Integer minMentions` + 캐시 키에 `mm=` 포함.
|
||||
|
||||
### 프론트
|
||||
6. `lib/api.ts` — `Restaurant.video_count?: number | null`; `getRestaurants` 파라미터 `min_mentions?`(미래/서버필터용).
|
||||
7. `app/page.tsx` — 필터 상태 `minMentions`(0/2/3/5) + `filteredRestaurants`에 `(r.video_count ?? 0) >= minMentions` 가드 + UI 컨트롤 + useMemo deps 추가.
|
||||
- **필터 리셋 일관성**: `minMentions`도 다른 필터(장르/가격/지역/채널)와 동일하게 취급.
|
||||
- 전역 "전체보기" 버튼: 노출 조건에 `minMentions > 0` 포함, 클릭 시 `setMinMentions(0)`로 함께 초기화.
|
||||
- "내위치" 토글 ON: 다른 필터 초기화 목록에 `setMinMentions(0)` 포함(내위치와 상호배타).
|
||||
데스크톱/모바일 토글 **전부**(3곳)에 동일 적용 — 반응형 리사이즈 시에도 일관.
|
||||
|
||||
## 엣지케이스
|
||||
- `video_count` 미산정(findById 등) → null. 클라 필터는 `?? 0`로 안전.
|
||||
- minMentions=0(기본) → 필터 미적용(기존 동작 유지).
|
||||
- DISTINCT + 스칼라 서브쿼리: r.id 단위라 결과 불변.
|
||||
|
||||
## 검증
|
||||
- 백엔드 빌드 성공 → PM2 재시작.
|
||||
- `GET /api/restaurants?min_mentions=2` 가 2회 미만 식당 제외하는지.
|
||||
- 응답에 `video_count` 포함 확인.
|
||||
- 프론트 토글로 목록/지도가 줄어드는지.
|
||||
86
docs/design/545-hide-foreign-reservation-buttons/README.md
Normal file
86
docs/design/545-hide-foreign-reservation-buttons/README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# 설계서: 해외 식당 예약 버튼(테이블링/캐치테이블) 숨김 (#545)
|
||||
|
||||
> **상태**: Approved · QA 통과 · Designer 접근성 다듬기 완료
|
||||
> **작성**: [AI] Architect (소급 작성 — Developer 구현 후 게이트 보완) · **최종수정**: 2026-07-27 ([AI] Designer)
|
||||
> **추적성** — Redmine: #545 · 관련 ADR: 없음
|
||||
> · 구현 파일: `frontend/src/components/RestaurantDetail.tsx` · 테스트: `frontend/__tests__/RestaurantDetail.test.tsx` (5케이스, 육안 QA를 자동화 회귀 테스트로 대체)
|
||||
|
||||
## 1. 목적 (Why)
|
||||
해외 식당 상세에 국내 전용 예약 서비스(테이블링/캐치테이블) 버튼이 노출되는 버그를 막는다.
|
||||
테이블링/캐치테이블은 국내 식당만 지원하므로, 해외 식당에서는 두 버튼을 숨겨야 한다.
|
||||
|
||||
## 2. 범위 (Scope)
|
||||
- **포함**: `RestaurantDetail.tsx`의 테이블링/캐치테이블 예약 버튼 2종에 국내 판정 게이트 적용.
|
||||
- **제외 (out of scope)**: 백엔드 예약 URL 검색/벌크 수집이 해외 식당을 제외하도록 하는 것 (#545 후속, 별도 이슈로 분리 가능).
|
||||
|
||||
## 3. 인수조건 (Acceptance Criteria)
|
||||
- [x] 해외 식당(좌표가 한국 bbox 밖) 상세에서 테이블링/캐치테이블 버튼이 보이지 않는다.
|
||||
- [x] 국내 식당 상세에서는 기존과 동일하게 두 버튼이 보인다 (URL 존재 시).
|
||||
- [x] `tsc` 타입체크 통과.
|
||||
- [x] QA 확인 (해외/국내 식당 각 1건 이상, 대표 발견 케이스 포함) — 자동화 회귀 테스트로 대체 검증 완료(`RestaurantDetail.test.tsx`).
|
||||
|
||||
## 4. 컨텍스트 & 제약
|
||||
- 의존성: `Restaurant.latitude/longitude`, `Restaurant.region` (좌표 없는 구 데이터 fallback).
|
||||
- 제약: 기존 지도 링크 분기(151행)에 이미 쓰이던 `isKoreaRestaurant()` 판정 기준과 동일하게 유지해야 함(판정 기준 이원화 방지).
|
||||
- 가정: `tabling_url`/`catchtable_url`이 `"NONE"`이 아니고 값이 있어도, 해외 식당이면 노출하지 않는다.
|
||||
|
||||
## 5. 아키텍처 개요
|
||||
- 변경 파일: `frontend/src/components/RestaurantDetail.tsx` 1개.
|
||||
- 데이터 흐름: `restaurant` prop → `isKoreaRestaurant(restaurant)` 순수 판정 → JSX 렌더 게이트.
|
||||
- I/O 없음, 순수 함수 기반 조건부 렌더링만 추가.
|
||||
|
||||
```
|
||||
Restaurant (좌표/region)
|
||||
│
|
||||
▼
|
||||
isKoreaRestaurant(r) ──false──▶ 테이블링/캐치테이블 버튼 미렌더
|
||||
│
|
||||
true
|
||||
│
|
||||
▼
|
||||
기존 로직: url 존재 && != "NONE" → 버튼 렌더
|
||||
```
|
||||
|
||||
## 6. 데이터 모델
|
||||
- 입력: `Restaurant { latitude?, longitude?, region?, tabling_url?, catchtable_url? }` (기존 타입, 변경 없음).
|
||||
- 출력: 없음 (렌더 분기만).
|
||||
- 경계 검증: `isKoreaRestaurant()` 내부에서 이미 null/undefined 가드 처리(좌표 없으면 region 첫 토큰 fallback).
|
||||
|
||||
## 7. 함수 명세 (Function Specs)
|
||||
|
||||
| 함수 | 책임(1줄) | 시그니처 | 입력 | 출력 | 에러/실패 | 복잡? |
|
||||
|------|-----------|----------|------|------|-----------|-------|
|
||||
| `isKoreaRestaurant` | 좌표/region 기반 국내 식당 판정 (기존 함수, 변경 없음 — 적용 범위만 확대) | `(r: Restaurant) => boolean` | `Restaurant` | `boolean` | 없음 (순수 함수) | 단순 |
|
||||
|
||||
> 신규 함수 없음. 기존 `isKoreaRestaurant()`(30행, 지도 링크 분기용으로 이미 존재)를 예약 버튼 2곳에도 동일 적용.
|
||||
|
||||
## 8. 흐름 / 알고리즘
|
||||
1. `isKoreaRestaurant(restaurant)` 평가 (좌표 우선, KR bbox 33~38.7°N / 124~132°E; 좌표 없으면 `region` 첫 토큰이 `"한국"`인지로 fallback).
|
||||
2. `true`일 때만 기존 조건(`tabling_url`/`catchtable_url` 존재 && `!== "NONE"`)을 이어서 평가.
|
||||
3. 최종 `true`일 때만 버튼 렌더.
|
||||
|
||||
## 9. 엣지케이스 & 에러 처리
|
||||
- 좌표와 region 모두 없는 구 데이터 → `isKoreaRestaurant`는 `!r.region` 조건으로 `true` 반환(국내로 간주, 기존 동작 유지 — 회귀 아님).
|
||||
- 좌표가 KR bbox 경계값에 걸치는 경우(제주/울릉도 등) → 기존 지도 링크 판정과 동일 로직이므로 별도 리스크 없음(기존에 검증된 임계값 재사용).
|
||||
|
||||
## 10. 테스트 계획
|
||||
- `tsc` 통과 (완료).
|
||||
- 자동화 회귀 테스트(`frontend/__tests__/RestaurantDetail.test.tsx`, RTL) — [AI] QA 작성, 5케이스 전부 통과:
|
||||
1. 국내 좌표(서울) + URL 존재 → 두 버튼 노출.
|
||||
2. 해외 좌표(방콕, 대표 발견 케이스) + URL 존재 → 두 버튼 숨김.
|
||||
3. 해외 좌표(도쿄) + URL 없음 → 숨김 유지(회귀 없음).
|
||||
4. 좌표 없음 + region null → fallback으로 국내 간주, 버튼 노출(기존 동작 유지).
|
||||
5. URL이 `"NONE"` 문자열 → 국내 식당이어도 버튼 없음(기존 게이트 유지).
|
||||
|
||||
## 11. 리스크 & 대안 검토
|
||||
- 대안: 백엔드에서 해외 식당의 `tabling_url`/`catchtable_url`을 애초에 null로 채우지 않는 방법도 있으나, 프론트 게이트가 더 즉각적이고 기존 판정 로직 재사용 가능 → 채택.
|
||||
- 되돌리기 어려운 결정 없음. ADR 불필요.
|
||||
|
||||
## 12. 미해결 질문 (Open Questions)
|
||||
- 백엔드 예약 URL 수집/검색 단계에서 해외 식당을 원천 제외할지 여부는 별도 이슈로 분리할 가치가 있음 (설명에 "후속(옵션)"으로 명시됨).
|
||||
|
||||
## 13. Designer 다듬기 (표현/접점, 기능 변경 없음)
|
||||
- 판정 로직(`isKoreaRestaurant`)과 노출 조건은 QA 통과 상태 그대로 — 변경하지 않음.
|
||||
- 테이블링/캐치테이블 앵커에 `title` 속성 추가(`"… (새 탭)"`) — 새 탭 이동을 사전에 알려 예약 흐름 중 예기치 않은 이탈감 완화.
|
||||
- 로고 대체용 단일 문자 배지(`T`/`C`)에 `aria-hidden="true"` 적용 — 스크린리더가 의미 없는 낱글자를 중복 낭독하지 않고 실제 라벨만 읽도록 정리.
|
||||
- 회귀 확인: `tsc --noEmit` 통과, `frontend/__tests__/RestaurantDetail.test.tsx` 5/5 통과.
|
||||
110
docs/ir/modu-startup-2026-09/README.md
Normal file
110
docs/ir/modu-startup-2026-09/README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# 모두의 창업 2차 — Tasteby 지원서 작업방
|
||||
|
||||
- **지원 아이템**: Tasteby — 신뢰하는 유튜버/유명인의 맛집을 AI가 자동 정리해 한 지도에 모아주는 디스커버리 플랫폼
|
||||
- **구분**: 2차 지원(재도전) — Q8 재도전 가점 항목 존재
|
||||
- **서비스**: https://www.tasteby.net (MVP 운영 중)
|
||||
|
||||
## 파일 구성
|
||||
|
||||
| 파일 | 역할 |
|
||||
|------|------|
|
||||
| `questions.md` | 지원서 문항 원문·제약 (고정, 수정하지 않음) |
|
||||
| `v1.md` | 최초 스냅샷 (보유 원고를 문항에 매핑) |
|
||||
| `v2.md` | Codex(gpt-5.6) 작성분을 이관 |
|
||||
| `v3.md` | v2에 실측 지표 반영 |
|
||||
| `v4.md` | Q8 완성 |
|
||||
| `v5.md` | 심사 기준에 맞춰 재정렬 |
|
||||
| `v6.md` | **현재 제출안**. Q5·Q11 완성 |
|
||||
| `q5-video-script.md` | 소개 영상 촬영 대본 (85초 9컷) |
|
||||
|
||||
## 버저닝 규칙
|
||||
|
||||
1. 수정할 때 이전 버전을 고치지 않는다. `cp v1.md v2.md` 후 v2를 고친다.
|
||||
2. 각 버전 머리말에 **무엇을 왜 바꿨는지** 한 줄씩 남긴다.
|
||||
3. 최종 제출 시 `FINAL.md` 로 복사하고, 실제 폼에 붙여넣은 시각을 기록한다.
|
||||
|
||||
## 버전 이력
|
||||
|
||||
| 버전 | 날짜 | 요약 |
|
||||
|------|------|------|
|
||||
| v1 | 2026-09-15 | 보유 원고를 12개 문항에 매핑한 최초 스냅샷. Q1/Q2는 폼 입력 원문 보존 |
|
||||
| v2 | 2026-09-15 | Codex 작성. 전 문항 작성 완료. "출처 기반 발견 → 비공개 기록 → 선택적 공유"로 논리 재편. Redmine #791 |
|
||||
| v6 | 2026-09-15 | Q11 공개 소개문 작성(517자), Q5 촬영 대본 별도 문서로 작성 |
|
||||
| v5 | 2026-09-15 | 심사 기준 확인 후 재정렬. Q4-1을 "2개월 내 MVP" 축으로 재구성(이미 운영 중임을 전면에), Q3-2에서 광고·캠페인 수익원 삭제, Q4-2·Q8 동반 수정 |
|
||||
| v4 | 2026-09-15 | Q8 완성 — 1차 원문이 `v1.md`임을 확인하고 1차의 약점 4가지와 2차 수정을 1:1 대응 |
|
||||
| v3 | 2026-09-15 | 실측 반영. Q4-1의 "3개월 5,000곳"(10배, 달성 불가) → 현재 500곳 기준 배수 목표로 교체. 미검증 1,071건 정리를 0~3개월 과제로. 해외 60여 곳을 Q3-1/Q4-1 근거로. 깨진 링크 3개 제거 |
|
||||
|
||||
## 현재 진척 (v2 기준, 글자수 실측)
|
||||
|
||||
| 문항 | 글자수 | 제한 | 상태 |
|
||||
|------|--------|------|------|
|
||||
| Q1 한 줄 소개 | 54 | 100 | 🟡 v1(62자)과 문구 다름 — 택1 필요 |
|
||||
| Q2 배경 이야기 | 996 | 2,000 | 🟡 폼에 든 v1 원문과 다름 — 교체 여부 결정 |
|
||||
| Q3-1 차별점 | 1,286 | 2,000 | ✅ v3에서 해외 데이터 근거 추가 |
|
||||
| Q3-2 수익 창출 | 765 | 2,000 | ✅ 광고 삭제, 크리에이터 축으로 단일화 |
|
||||
| Q4-1 사업화 계획 | 1,100 | 2,000 | ✅ v5에서 "2개월 내 MVP" 축으로 재구성 |
|
||||
| Q4-2 멘토 도움 | 888 | 2,000 | ✅ |
|
||||
| Q5 소개 영상 | 대본 완성 | - | ⬜ 촬영·편집만 남음 (`q5-video-script.md`) |
|
||||
| Q6 사업 분야 | 선택 기준 | - | ⬜ 드롭다운 실물 확인 |
|
||||
| Q7 창업 여부 | 판단표 | - | ⬜ 법적 사실 확인 |
|
||||
| Q8 1차 대비 개선점 | 1,171 | - | ✅ |
|
||||
| Q9 본인 역량 | 916 | 2,000 | 🟡 경력·배경 한 단락 추가 여지 |
|
||||
| Q10 팀원 수 | - | - | ✅ 팀원 없음 |
|
||||
| Q11 자랑하기 | 517 | - | ✅ v6 완성 / 스크린샷 1장 필요 |
|
||||
| Q12 서약 동의 | - | - | ⬜ 제출 직전 |
|
||||
|
||||
## v2 검증 결과 (2026-09-15)
|
||||
|
||||
**사실로 확인된 것**
|
||||
- 찜·공개 리뷰·비공개 메모 기능 실존: `MemoController`/`MemoService`(사용자별, 공개 엔드포인트 없음), `ReviewController`, 프론트 `RestaurantDetail.tsx`
|
||||
- MVP 운영 중: PM2 `tasteby-api`/`tasteby-web` 가동, www.tasteby.net
|
||||
|
||||
**확인되지 않은 것**
|
||||
- v2 머리말의 참조 문서 3개(`docs/design/705-tasteby-bm-v1-1/`, `docs/strategy/tasteby-personalization-…`, `docs/design/711-tasteby-marketing-v1-5/`)가 **리포에 없음**
|
||||
- Codex가 보고한 산출 경로 `docs/applications/moduui-changup-round2/`, 워크트리 `~/claude-workspace/business-model`, 커밋 `f50bbab` 모두 이 머신에 **없음** (Redmine #791은 실존)
|
||||
- 로드맵 수치(식당 5,000곳/채널 10곳/MAU 5만)의 출발점이 될 현재 실측치 미확인
|
||||
|
||||
## 남은 과제 (우선순위)
|
||||
|
||||
1. **Q1·Q2 택1** — 폼에는 v1 문구가 이미 들어가 있음. v3 문구로 교체할지 결정.
|
||||
2. **Q3-2에 숫자** — 원칙은 섰으나 단가·매출 추정이 없어 "언제 돈을 버는가"가 불명확.
|
||||
3. **Q4-1 획득 경로** — "검색·커뮤니티·콘텐츠"가 아직 범주 수준. 다만 v3에서 공개 모집 전 단계임을 명시해 과장은 제거됨.
|
||||
4. **Q5 영상** — 대본 완성, 촬영·편집 남음.
|
||||
5. **사진 8장 확보** — 도식 3장 제작 필요.
|
||||
6. **Q9 경력 보강**
|
||||
7. **미배포 15커밋** — Q8이 언급한 개선(#532/#533/#545)이 main에만 있고 운영 미반영. 제출 전 배포 필요 — 공개 가능한 경력·수상이 있으면 한 단락.
|
||||
|
||||
## 실측 지표 (2026-09-15 확인)
|
||||
|
||||
| 항목 | 현재 | 확인 방법 |
|
||||
|------|------|-----------|
|
||||
| 등록 채널 | **6개** | Admin 채널 관리 |
|
||||
| 수집 영상 | **909편** | 채널별 합계 (성시경52·김사원세끼270·더들리188·떡볶퀸92·비밀이야196·버거코치111) |
|
||||
| 노출 식당 | **500곳** | `GET /api/restaurants?limit=100000` |
|
||||
| 좌표 보유 | 500/500 (100%) | 동 API |
|
||||
| 해외 식당 | 일본 28 · 미국 9 · 싱가포르 8 · 이탈리아 4 · 홍콩 3 (국내 417) | region 집계 |
|
||||
| 2회 이상 언급 | 63곳 (3회 이상 21곳) | `video_count` 집계 |
|
||||
| LLM 미검증 | 1,071건 | Admin 식당 관리 |
|
||||
| 가입자 수 | **공개 모집 전** | 지원서에 수치로 쓰지 않고, "제품·데이터 우선 확보 단계"로 서술 |
|
||||
|
||||
**로드맵 대비 위치**: 채널 6→10(1.7배). 식당 500→5,000은 10배로, 채널당 평균 83곳 기준 채널 60개 수준의 커버리지를 요구해 3개월 내 달성 불가 → **v3에서 1,500곳으로 조정하고 0~3개월 과제를 미검증 1,071건 정리로 재정의함**.
|
||||
|
||||
## 심사 기준 (2026-09-15 확인)
|
||||
|
||||
- 주최: **중소벤처기업부 대국민 창업 오디션**. 일반/기술트랙 4,000명 + 로컬트랙 1,000명 선발
|
||||
- 진출 혜택: 창업활동자금 200만 원 + 책임멘토링 + AI 바우처. 이후 라운드별 MVP 제작비(최대 1,000만)→사업화자금(최대 1억)→우승 상금 5억
|
||||
- 심사 3축: **도전의 진정성 / 사회적 가치(독창성·차별성) / 아이디어 구체성(BM 현실성·단계별 로드맵)**
|
||||
- 거의 모든 멘토기관 공통 항목: **"창업활동자금과 AI 솔루션을 활용해 2개월 내 MVP 제작이 가능한 수준인가"**
|
||||
- 함의: 이 단계는 수익모델의 정교함을 다투는 자리가 아니다. **이미 운영 중인 MVP가 최대 강점**이므로 Q4-1·Q9에 힘을 싣고, 선택 문항인 Q3-2는 원칙만 짧게.
|
||||
- 출처: modoo.or.kr, 멘토기관 80여 곳 평가지표 정리 자료
|
||||
|
||||
## 수익모델 결정 (v5)
|
||||
|
||||
- **하지 않는 것**: 검색·추천 순위 판매, 노출형 광고 — 유명 큐레이터 추천이 강점인 서비스에 붙이면 Q3-1에서 비판한 기존 서비스와 같아진다
|
||||
- **축**: 크리에이터 파트너십 (채널 공식 페이지 + 성과 배분). 이미 영상에서 추천된 가게를 다루므로 추천의 순수성이 유지되고, 크리에이터에게 홍보 동기가 생긴다
|
||||
- **조건부**: 예약·주문 제휴 수수료. 현재 DB에 테이블링 225곳·캐치테이블 142곳 링크가 있으나 **외부 서비스용 제휴 프로그램 존재가 확인되지 않음** → 확인 전까지 수익원으로 단정하지 않는다
|
||||
|
||||
## 참고 자산
|
||||
|
||||
- `docs/ir/bunkershot-2026-06-29/` — 6월 벙커샷 IR 자료 (피치덱, 1pager, 예상 QA, 시연 시나리오). Q5 영상 대본·Q3 소재로 재활용 가능
|
||||
- `screenshots/` — 서비스 스크린샷 (사진 첨부용, 전체 합산 10장 제한)
|
||||
27
docs/ir/modu-startup-2026-09/q5-video-script.md
Normal file
27
docs/ir/modu-startup-2026-09/q5-video-script.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Q5 소개 영상 대본 (85초)
|
||||
|
||||
> 제출물은 유튜브 URL 하나. 이 문서는 **촬영용**이다.
|
||||
> 촬영 원칙: Tasteby 실제 화면과 직접 만든 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원은 넣지 않는다.
|
||||
> 권장 방식: 화면 녹화(QuickTime) + 자막. 목소리 녹음이 부담되면 **자막만으로도 성립**하도록 문장을 짧게 썼다.
|
||||
|
||||
## 컷 구성
|
||||
|
||||
| # | 시간 | 화면 | 자막 / 내레이션 |
|
||||
|---|------|------|-----------------|
|
||||
| 1 | 0:00–0:08 | 유튜브 앱에서 맛집 영상 목록을 빠르게 스크롤. 재생바를 앞뒤로 끄는 모습 | "그 영상에서 봤던 그 국밥집,<br>이름이 뭐였더라." |
|
||||
| 2 | 0:08–0:15 | 영상 자막을 멈춰 세우고 가게 이름을 메모앱에 옮겨 적는 손 | "매번 영상을 되감고,<br>받아 적고, 지도에 옮겼습니다." |
|
||||
| 3 | 0:15–0:22 | 화면 전환 → Tasteby 지도. 핀이 한꺼번에 뜨는 장면 | "그래서 만들었습니다.<br>**Tasteby**" |
|
||||
| 4 | 0:22–0:32 | 채널 필터에서 특정 채널 선택 → 지도의 핀이 그 채널 것만 남는 장면 | "내가 믿는 채널로 먼저 좁힙니다.<br>떡볶이가 먹고 싶으면 분식을 다루는 채널로." |
|
||||
| 5 | 0:32–0:45 | 식당 마커 클릭 → 상세 시트. 유튜버 평가와 언급 메뉴, 원본 영상 링크를 천천히 보여줌 | "그 사람이 **어떤 영상에서 뭐라고 했는지** 그대로 남습니다.<br>의심되면 원본으로 돌아가면 됩니다." |
|
||||
| 6 | 0:45–0:55 | 찜 버튼 누르기 → 비공개 메모에 한 줄 적기 | "다녀온 뒤엔 나만 보는 메모로 남깁니다.<br>공개 리뷰가 아니라, 다음 식사를 위한 기록입니다." |
|
||||
| 7 | 0:55–1:05 | 지역 필터를 일본으로 → 도쿄 지도에 핀이 뜨는 장면 | "여행지에서도 똑같습니다.<br>낯선 리뷰를 처음부터 읽는 대신,<br>믿는 사람의 선택을 그대로 꺼냅니다." |
|
||||
| 8 | 1:05–1:15 | 언급 횟수 필터를 3회 이상으로 → 목록이 확 줄어드는 장면 | "여러 번 언급된 집만 보는 것도 가능합니다.<br>한 번 스쳐 간 곳과 진짜 추천을 구분합니다." |
|
||||
| 9 | 1:15–1:25 | 직접 만든 숫자 카드 (채널 6 / 영상 909 / 식당 500) → 마지막에 도메인 | "채널 6곳, 영상 909편에서<br>식당 500곳을 이미 모았습니다.<br>혼자 만들어 운영 중입니다.<br>**www.tasteby.net**" |
|
||||
|
||||
## 촬영 메모
|
||||
|
||||
- **컷 5가 핵심이다.** 다른 서비스와 갈리는 지점이므로 여기에 시간을 가장 많이 준다. 별점이 아니라 "누가, 어디서, 뭐라고 했는지"가 보이는 화면을 크게.
|
||||
- 컷 1~2는 스마트폰 촬영으로 충분하다. 손으로 되감고 받아 적는 장면이 있어야 컷 3의 해방감이 산다.
|
||||
- 유튜브 화면을 그대로 쓰기 어렵다면, 컷 1~2는 **직접 만든 도식**(영상 아이콘 → 물음표 → 메모장)으로 대체해도 메시지는 유지된다.
|
||||
- 배경음악은 저작권이 자유로운 음원만 사용한다(유튜브 오디오 보관함).
|
||||
- 마지막 컷의 숫자는 **제출일 기준으로 다시 확인**해서 넣는다.
|
||||
26
docs/ir/modu-startup-2026-09/questions.md
Normal file
26
docs/ir/modu-startup-2026-09/questions.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 모두의 창업 2차 — 지원서 문항 원문
|
||||
|
||||
> 출처: 지원서 작성 화면 캡처 (2026-09-15 확인)
|
||||
> 이 파일은 **문항 원문 보존용**이다. 답변은 `vN.md` 에 쓴다.
|
||||
|
||||
| 문항 | 필수 | 글자수 | 비고 |
|
||||
|------|------|--------|------|
|
||||
| Q1. 나의 아이디어를 한 줄로 소개해주세요. | 필수 | 10~100자 | |
|
||||
| Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. | 필수 | 2,000자 | 사진 첨부 가능 |
|
||||
| Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? | 필수 | 2,000자 | 사진 첨부 가능 |
|
||||
| Q3-2. 어떻게 수익을 창출할 계획인가요? | 선택 | 2,000자 | 사진 첨부 가능 |
|
||||
| Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? | 필수 | 2,000자 | 사진 첨부 가능 |
|
||||
| Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? | 선택 | 2,000자 | 사진 첨부 가능 |
|
||||
| Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. | 선택 | URL | **유튜브 링크만** |
|
||||
| Q6. 사업 분야를 선택해주세요. | 필수 | 드롭다운 | |
|
||||
| Q7. 지원자의 현재 창업 여부를 알려주세요. | 필수 | 택1 | 예비창업자 / 기창업자 |
|
||||
| Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? | 선택 | - | **재도전 가점 반영** |
|
||||
| Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. | 선택 | 2,000자 | |
|
||||
| Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. | 선택 | 드롭다운 | 기본값 "팀원 없음" |
|
||||
| Q11. 내 아이디어를 사람들에게 자랑해보세요. | 선택 | - | **홈페이지 공개 + 좋아요** |
|
||||
| Q12. 서약서 동의 | 필수 | 체크 | 참여/본인아이디어/비밀유지 |
|
||||
|
||||
## 운영 제약
|
||||
- **사진은 전체 문항 합산 최대 10장.** 문항별이 아니라 총량 제한이므로 배분 계획 필요.
|
||||
- Q7 기창업자 기준: 창업일이 **2019.08.21.~2026.08.20.** 범위이고, 기존 사업과 **다른 아이템(이종창업)** 희망자.
|
||||
- Q8/Q11은 선택이지만 각각 **가점**과 **공개 노출** 효과가 있어 실질적으로 작성 권장.
|
||||
163
docs/ir/modu-startup-2026-09/v1.md
Normal file
163
docs/ir/modu-startup-2026-09/v1.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# 모두의 창업 2차 지원서 — v1 (초안 스냅샷)
|
||||
|
||||
- **작성일**: 2026-09-15
|
||||
- **상태**: 보유 원고를 문항에 매핑한 최초 스냅샷. 문장 다듬기·수치 검증은 v2에서.
|
||||
- **원칙**: Q1/Q2는 **이미 폼에 입력된 원문 그대로** 보존(오타 포함). 손대지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 100자)
|
||||
|
||||
내가 신뢰하는 유튜버/유명인의 맛집을, AI가 영상/글에서 자동으로 정리해 한 지도에 모아주는 디스커버리 플랫폼
|
||||
|
||||
> [현황] 폼 입력 완료 (63자). 원문 유지.
|
||||
|
||||
---
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
평소 유튜브로 맛집 영상을 자주 보는 한 사람으로서, 한 가지 반복되는 답답함이 있었습니다. "성시경 채널에서 본 그 가게, 어디였더라?" 영상을 다시 뒤져 자막에서 가게 이름을 받아 적고, 지도에 옮겨야 합니다. 좋아하는 채널 5개만 구독해도 한 달치 영상이 수십 개. 그중 정작 가고 싶은 가게를 다시 꺼내는 일은 사실 불편하고 번거로웠습니다.
|
||||
|
||||
기존 맛집 서비스를 써봐도 갈증은 풀리지 않았습니다. 익명 다수의 별점에 의존하는 서비스는 가짜 리뷰 논란이 끊이지 않고, 광고성 콘텐츠가 상위에 노출됩니다. 정작 제가 신뢰하는 사람, 음식을 진심으로 다루는 유튜버의 추천은 그 어디에도 정리되어 있지 않았습니다. 이 문제는 해외여행 때 더 극심해졌습니다. 일본 여행을 준비하며 성시경의 일본 맛집 시리즈를 다 보고 갔지만, 정작 도쿄 거리에서 그 가게를 찾는 데 오랜 시간이 걸렸습니다. 영상 속 정보가 활용에는 그 식당을 언급하는 장면을 다시 돌려본다던가 하는 불편함이 있어 쉽지 않았습니다. 그래서 이런생각을 했습니다. "신뢰하는 사람의 선택을 한 지도에 모아주는 서비스." 그러나 손으로 정리하는 건 불가능합니다. 영상 한 편에서 식당 정보를 추출하는 데 사람이 30분씩 걸리는데, 한 채널만 해도 영상이 수백 개입니다.
|
||||
|
||||
LLM(거대언어모델)의 발전이 이 문제를 해결해 주었습니다. 영상 자막을 LLM에 넣으면 식당 정보를 구조화해 추출할 수 있고, 추출한 주소를 지오코딩해 지도에 꽂으면 됩니다. 더 이상 사람이 손으로 정리할 필요가 없습니다. 이 깨달음이 Tasteby의 출발점입니다. 기술이 가능하게 만든 "신뢰 기반 큐레이션" 알고리즘이 아닌 사람의 신뢰를, 기계가 자동으로 정리해 모두에게 열어주는 플랫폼입니다.
|
||||
|
||||
> [현황] 폼 입력 완료 (854자). 원문 유지.
|
||||
> [v2 검토 예정] 마지막 문단 두 문장(“영상 속 정보가 활용에는…”, “기술이 가능하게 만든 …열어주는 플랫폼입니다.”)이 비문. 2,000자 중 854자만 사용 — 여유 1,100자.
|
||||
|
||||
---
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
**1차 타겟: 외식·맛집에 진심인 한국인**
|
||||
20~40대 약 1,500만 명. 유튜브 맛집 콘텐츠를 일상적으로 소비하지만, 영상 속 정보가 분산되어 있어 정작 가고 싶을 때 활용하지 못합니다. "그 곱창집이 어디였지?", "이 셰프가 추천한 동네 중식당이 어디였더라?" 매번 영상을 거꾸로 돌려 찾아야 합니다.
|
||||
|
||||
**2차 타겟: 해외여행을 자주 가는 한국인**
|
||||
연 700만 명 이상의 일본 여행객을 비롯해, 좋아하는 한국 유튜버의 해외 콘텐츠를 신뢰하는 사람들. 익명의 외국 리뷰 사이트보다 자신이 신뢰하는 한국 유튜버의 추천을 따르고 싶지만, 현지에서 그 정보를 활용할 도구가 없습니다.
|
||||
|
||||
**3차 타겟: 콘텐츠를 만드는 유튜버**
|
||||
음식 콘텐츠 크리에이터는 자신이 다녀온 가게가 영상 한 편으로 소비되고 끝납니다. 새로운 시청자가 그 가게를 나중에 검색해도 영상에 도달하지 않습니다. 자신의 큐레이션이 자산화되지 않는 구조입니다.
|
||||
|
||||
**기존 서비스가 풀지 못한 이유**
|
||||
- 망고플레이트·다이닝코드: 익명 리뷰 의존 → 신뢰 붕괴
|
||||
- 캐치테이블: 예약 중심 → 발견 기능 약함
|
||||
- 구글 지도: 별점 평균만 표시 → "누가" 추천했는지 알 수 없음
|
||||
- 유튜브 직접 검색: 정작 위치·주소 정보가 영상 속에 묻혀있음
|
||||
|
||||
**Tasteby가 해결하는 본질**
|
||||
사용자에게는 "신뢰하는 사람의 선택"이 한 지도에 정리되어 보입니다. 가게를 클릭하면 그 유튜버가 영상에서 어떤 평가를 했는지 즉시 확인하고, 원본 영상으로 회귀할 수 있습니다.
|
||||
|
||||
결정적 차별화는 **"분야별 전문 큐레이터" 포지셔닝**입니다. 성시경은 노포·국밥 전문, 더틀리는 호텔·파인다이닝, 떡볶퀸은 분식 전문, 버거코치는 햄버거 전문 같이 각 채널을 분야별 권위자로 포지셔닝합니다. 사용자는 "오늘은 떡볶이가 먹고 싶다 → 떡볶퀸이 검증한 가게"라는 직관적 경로를 가지고, 유튜버는 자신의 전문성을 명확한 정체성으로 자산화합니다. 잡지 에디터 모델을 디지털·자동화로 옮긴 구조이고, 이것은 국내 이용자와 해외 여행자 모두에게 동일하게 적용됩니다.
|
||||
|
||||
**핵심 기술: LLM 자동 추출 + 벡터 시맨틱 검색**
|
||||
YouTube 자막·메타데이터 수집 → OCI GenAI(LLM)가 식당명·주소·메뉴·유튜버 평가를 구조화 추출 → Cohere Embed v4로 벡터 임베딩 후 Oracle 23ai Vector DB 저장 → 키워드가 아닌 의미 기반 유사도 검색으로 큐레이션. "혼술하기 좋은 분위기", "성시경 스타일의 노포" 같은 의미 단위 질의가 가능합니다.
|
||||
|
||||
> [현황] 폼 미입력. 보유 원고를 배치한 상태.
|
||||
> [v2 검토 예정] 분량 초과 여부 확인 → 아래 글자수 표 참조. 타겟 3종을 앞세우는 현재 구성은 "차별점" 질문에 대한 답이 뒤에 나오므로, **차별점을 먼저 → 타겟은 압축**하는 재배치 검토.
|
||||
|
||||
---
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
**수익 모델 (3단계 점진 확장)**
|
||||
- 단기: 유튜버 큐레이터 파트너십(채널 페이지 + 수익 분배), 식당 B2B 제휴(검증된 노출/예약)
|
||||
- 장기: 글로벌 확장(일본→동남아), 외식 트렌드 데이터 인사이트 B2B
|
||||
|
||||
> [현황] 폼 미입력. **원고 부족** — 현재 2줄. 2,000자 대비 태부족.
|
||||
> [v2 필수 보강] ① 3단계인데 단기/장기 2개만 기술됨(중기 누락). ② 단가·과금 방식·예상 매출 규모 없음. ③ "12개월에 첫 매출 발생" 로드맵과 연결 필요.
|
||||
|
||||
---
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
**현재 단계: MVP 운영 중**
|
||||
- 도메인: www.tasteby.net (안정 가동 중)
|
||||
- 기술 스택: Spring Boot 3.3 + Java 21, Next.js 16, Oracle 23ai 벡터 DB, Redis, Kubernetes(OKE) — 프로덕션 인프라 구축 완료
|
||||
- 구현 기능: LLM 식당 정보 추출, YouTube 자막 처리, 지오코딩, 클러스터링 지도, 회원·찜·리뷰·메모, 모바일 최적화, 자체 디자인 시스템(Saffron)
|
||||
- 풀스택 1인 개발자가 설계·구현·배포 전 과정을 완료한 검증된 실행력 보유
|
||||
|
||||
**12개월 단계별 로드맵**
|
||||
- 3개월: 식당 DB 5,000+, 등록 유튜브 채널 10+
|
||||
- 6개월: 일본 식당 베타 출시, 유튜버 큐레이터 파트너십 3건 체결
|
||||
- 12개월: MAU 5만, B2B 식당 제휴 20건, 첫 매출 발생
|
||||
|
||||
Tasteby의 경쟁우위는 "모든 가게의 평균"이 아닌 **"분야별 권위자의 검증된 모음"**입니다. 채널의 전체 영상을 LLM이 분석해 전문성을 자동 태깅/큐레이션합니다.
|
||||
|
||||
> [현황] 폼 미입력. 보유 원고를 배치한 상태.
|
||||
> [v2 검토 예정] ① "MAU 5만"에 도달하는 **획득 경로(마케팅)** 가 비어 있음 — 심사에서 가장 먼저 찔릴 지점. ② 유튜버 파트너십 3건의 **접근 방법**(저작권/초상 이슈 포함) 필요. ③ 현재 실측 지표(식당 수/채널 수/가입자) 기재 시 설득력 급상승.
|
||||
|
||||
---
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
**본 사업 자금·멘토링 활용 계획**
|
||||
1. 인플루언서 파트너십 확보 — 계약·법무 비용, 채널별 큐레이션 페이지 개발
|
||||
2. LLM 처리 인프라 확장 — 영상 처리량 10배 확대
|
||||
3. 글로벌 확장 — 다국어·다지역 처리 모듈 개발 (일본 우선)
|
||||
|
||||
> [현황] 폼 미입력. 현재 원고는 **자금 사용 계획**이지 "멘토에게 받고 싶은 도움"이 아님.
|
||||
> [v2 필수 재작성] 멘토 질문에 맞게 전환: 크리에이터 IP 계약 실무, 콘텐츠 인용 저작권 자문, B2B 식당 영업 채널, 초기 트래픽 획득 전략 등 **1인 개발자가 못 메우는 영역** 중심으로. 자금 사용 계획은 Q4-1로 이동 검토.
|
||||
|
||||
---
|
||||
|
||||
## Q5. 아이디어 소개 영상 (선택 / 유튜브 링크)
|
||||
|
||||
> [미정] 제작 여부 결정 필요. 기존 `docs/ir/bunkershot-2026-06-29/04-시연-시나리오.md` 를 대본 베이스로 재활용 가능.
|
||||
|
||||
---
|
||||
|
||||
## Q6. 사업 분야 (필수 / 드롭다운)
|
||||
|
||||
> [미정] 선택지 목록 확인 필요. 후보: 플랫폼/O2O, AI·데이터, 관광·여행, 푸드테크.
|
||||
|
||||
---
|
||||
|
||||
## Q7. 현재 창업 여부 (필수 / 택1)
|
||||
|
||||
> [미정] 예비창업자 / 기창업자 — 본인 확인 필요.
|
||||
|
||||
---
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
> [미작성] **1차 지원서 원문이 리포에 없음.** 원문 확보 후 작성.
|
||||
> 작성 축(안): ① 1차 이후 실제 개발 진척(프로덕션 배포, 기능 추가), ② 포지셔닝 구체화("분야별 전문 큐레이터" 개념), ③ 수익모델 단계화, ④ 1차 심사 피드백 반영 내용.
|
||||
|
||||
---
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량 (선택 / 2,000자)
|
||||
|
||||
> [미작성] 소재: 풀스택 1인 개발자로 설계→구현→운영 배포 전 과정 완수. Spring Boot/Next.js/Oracle 23ai 벡터 DB/Kubernetes(OKE) 프로덕션 운영. LLM 파이프라인 직접 구축. 8단계 AI 페르소나 개발 파이프라인 등 **혼자서도 팀 수준 산출물을 내는 운영 체계** 보유.
|
||||
> [확인 필요] 경력·이력(직장/프로젝트), 수상·자격 등 서술 가능한 배경.
|
||||
|
||||
---
|
||||
|
||||
## Q10. 팀원 수 (선택)
|
||||
|
||||
팀원 없음
|
||||
|
||||
---
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개)
|
||||
|
||||
> [미작성] 공개 노출 + 좋아요 대상. Q1의 한 줄 + 실제 서비스 링크(www.tasteby.net) + 스크린샷 조합으로 짧고 감각적으로. 심사문서 톤이 아니라 **일반 독자 대상 톤**.
|
||||
|
||||
---
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
> 제출 직전 체크: 참여 서약서 / 본인 아이디어 확인 서약서 / 비밀유지 서약서.
|
||||
|
||||
---
|
||||
|
||||
## 사진 배분 계획 (전체 합산 10장 제한)
|
||||
|
||||
| 문항 | 장수(안) | 내용 |
|
||||
|------|---------|------|
|
||||
| Q2 | 1 | "영상 → 지도" 문제 상황 대비 이미지 |
|
||||
| Q3-1 | 3 | 지도 화면, 식당 상세(유튜버 평가), 채널별 큐레이션 |
|
||||
| Q4-1 | 2 | 아키텍처 다이어그램, 로드맵 |
|
||||
| Q11 | 2 | 대표 스크린샷(모바일/데스크톱) |
|
||||
| 예비 | 2 | |
|
||||
|
||||
> [확인 필요] 스크린샷은 `screenshots/` 디렉토리 기존 자산 활용 가능 여부 점검.
|
||||
184
docs/ir/modu-startup-2026-09/v2.md
Normal file
184
docs/ir/modu-startup-2026-09/v2.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# 모두의 창업 2차 지원서 — v2 개선안
|
||||
|
||||
> 작성일: 2026-09-15
|
||||
> 상태: 문항별 붙여넣기 초안. `제출 전 확정` 표기가 있는 항목은 사실 확인 뒤에만 확정한다.
|
||||
> 수익·사업화의 근거: [Tasteby BM v1.1](../../design/705-tasteby-bm-v1-1/README.md), [개인화 전략](../../strategy/tasteby-personalization-as-taste-translation.md), [공유 성장 루프](../../design/711-tasteby-marketing-v1-5/README.md)
|
||||
|
||||
> ⚠️ **[2026-09-15 검증] 위 참조 문서 3개는 현재 리포에 존재하지 않는다.** Redmine #705/#711 이슈는 열려 있으나(08-Documenter) 문서 파일이 없다. 링크를 살리려면 문서를 작성하거나, 링크를 제거해야 한다.
|
||||
|
||||
## v1 → v2 변경 요약
|
||||
- Q1: 한 줄 소개를 "AI 자동 정리 플랫폼" → "발견에서 나의 기록으로 연결" 관점으로 교체
|
||||
- Q2: 비문 정리 + "다시 쓸 수 있게"라는 문제 정의로 재구성
|
||||
- Q3-1: 타겟 나열 → 차별점 3가지(출처 있는 발견 / 큐레이터 기준 탐색 / 비공개 맛 기억) 구조로 재배치
|
||||
- Q3-2: 111자 → 수익 원칙 + 4개 수익원의 단계적 검증 순서로 전면 작성
|
||||
- Q4-1: 로드맵 나열 → 쐐기시장(큐레이터 1 × 지역 1 × 메뉴 1) 전제의 0-3/4-6/7-12개월 검증 계획
|
||||
- Q4-2: 자금 사용 계획 → 멘토에게 받을 도움 4가지로 재작성
|
||||
- Q5~Q12: 전부 신규 작성 (영상 구성안, 분야 선택 기준, Q7 판단표, Q8 재도전 답안 틀, Q9 역량, Q11 공개 소개문, 사진 배분)
|
||||
|
||||
---
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 10~100자)
|
||||
|
||||
> 신뢰하는 미식 큐레이터의 영상 속 맛집을 찾아, 나의 다음 식사와 기록으로 연결하는 Tasteby
|
||||
|
||||
- v2 검증: 54자. 제출 화면의 실제 글자 수를 최종 확인한다.
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
저는 맛집 영상을 보는 것을 좋아하지만, 막상 식사 약속이 잡히면 같은 문제를 반복해서 겪었습니다. "성시경 영상에서 본 그 국밥집이 어디였지?" 기억나는 것은 사람과 메뉴의 인상뿐이었습니다. 다시 영상을 찾아 자막을 넘기고, 식당 이름을 받아 적어 지도에 옮겨야 했습니다. 좋아하는 채널이 늘수록 저장한 정보도 늘었지만, 정작 필요한 순간에는 더 찾기 어려워졌습니다.
|
||||
|
||||
이 불편은 일본 여행에서 더 선명해졌습니다. 여행 전에 한국 미식 유튜버의 일본 맛집 영상을 여러 편 봤지만, 현지에서는 어느 영상의 어느 장면에 나온 식당인지 다시 찾는 데 시간이 들었습니다. 별점과 후기 수가 많은 식당은 쉽게 찾을 수 있었지만, 제가 실제로 궁금했던 것은 "내가 신뢰하는 이 사람이 왜 이곳을 골랐는가"였습니다. 영상, 지도, 메모앱이 각각 답의 일부만 갖고 있었습니다.
|
||||
|
||||
그래서 출발한 질문은 "맛집을 더 많이 모으려면 어떻게 해야 할까?"가 아니었습니다. **신뢰하는 사람의 선택을, 다음 식사를 고를 때 다시 쓸 수 있게 하려면 어떻게 해야 할까?**였습니다.
|
||||
|
||||
Tasteby는 미식 큐레이터의 영상·글 속 식당, 메뉴, 언급 맥락을 구조화해 지도와 탐색 화면에서 찾게 하는 서비스입니다. 사용자는 원본 콘텐츠로 다시 돌아가 맥락을 확인할 수 있고, 마음에 드는 곳은 자신의 찜과 비공개 메모에 남길 수 있습니다. 즉, Tasteby는 원본 영상을 대체하거나 익명 다수의 평가를 더 크게 만드는 서비스가 아니라, 흩어진 신뢰의 단서를 실제 외식 결정에 쓸 수 있게 연결하는 도구입니다.
|
||||
|
||||
AI는 이 일을 가능하게 하는 수단입니다. 영상 자막과 공개 정보를 바탕으로 식당 후보를 구조화하되, 원본 출처를 남기고 오류는 정정할 수 있게 설계합니다. 저는 "AI가 맛집을 대신 추천한다"보다 "사람이 쌓아 온 신뢰를 사용자가 다시 쓸 수 있게 한다"는 방향이 더 오래 갈 수 있다고 믿습니다. Tasteby는 좋은 한 끼를 찾는 순간과, 좋았던 한 끼를 다시 기억하는 순간을 하나의 경험으로 만들고자 합니다.
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 또 하나의 맛집 순위 서비스가 아닙니다. 출발점이 "평점이 높은 곳은 어디인가?"가 아니라 **"내가 신뢰하는 사람이 어느 콘텐츠에서, 어떤 메뉴를, 왜 언급했는가?"**이기 때문입니다.
|
||||
|
||||
기존 맛집 서비스는 대체로 다수 이용자의 별점·후기, 예약 가능 여부, 지역 검색을 중심으로 설계돼 있습니다. 이 방식은 넓은 선택지를 빠르게 보여 주는 데 유용하지만, 영상을 보고 특정 사람의 선택을 기억한 사용자에게는 두 가지 공백이 남습니다. 첫째, 영상 속 식당의 이름·주소·메뉴가 콘텐츠 안에 흩어져 있어 나중에 다시 찾기 어렵습니다. 둘째, 평균 별점만으로는 왜 그 사람이 그 식당을 언급했는지, 내가 오늘 갈 이유가 있는지 판단하기 어렵습니다.
|
||||
|
||||
Tasteby의 차별점은 세 가지입니다.
|
||||
|
||||
첫째, **출처가 있는 발견**입니다. 식당을 보여 줄 때 원본 콘텐츠와 메뉴·언급 맥락을 함께 연결합니다. 사용자는 Tasteby의 요약만 믿을 필요 없이 원본으로 돌아가 확인할 수 있습니다. 추천인지 단순 언급인지, 협찬 또는 정정 정보가 확인되는 경우에는 이를 구분해 보이는 방향으로 신뢰를 설계합니다.
|
||||
|
||||
둘째, **분야별 큐레이터의 선택을 탐색 기준으로 사용**합니다. 사용자는 무작위 목록이 아니라 자신이 신뢰하는 미식 큐레이터, 먹고 싶은 메뉴, 갈 지역을 함께 놓고 후보를 좁힐 수 있습니다. 이는 "유명해서"가 아니라 특정 음식과 상황을 꾸준히 다뤄 온 사람의 관점을 발견의 출발점으로 삼는 방식입니다.
|
||||
|
||||
셋째, **개인의 맛 기억을 기본 비공개로 보존**합니다. 사용자는 방문 뒤 좋았던 이유와 다음에 갈 조건을 자기 메모로 남길 수 있습니다. 공개 리뷰를 많이 쓰게 하는 대신, 먼저 나를 위한 기록이 다음 선택에 다시 쓰이도록 하는 것이 목표입니다. 나중에 사용자가 원할 때만 일부 후보를 동행에게 공유할 수 있으며, 비공개 메모는 공유되지 않습니다.
|
||||
|
||||
Tasteby가 해결하려는 문제는 정보 부족이 아니라 **신뢰할 만한 정보를 다시 쓸 수 없는 문제**입니다. 음식 콘텐츠를 보는 사람은 다음 식사를 더 쉽게 결정하고, 크리에이터는 자신의 콘텐츠가 일회성 조회를 넘어 정정 가능하고 탐색 가능한 아카이브로 이어질 수 있습니다. AI는 이 구조를 빠르게 만들지만, 경쟁력의 핵심은 AI 자체가 아니라 출처를 보존하고 개인의 선택으로 이어 주는 제품 경험입니다.
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
Tasteby의 수익 원칙은 분명합니다. **사용자의 비공개 찜과 메모를 판매하지 않고, 돈을 낸 식당이 자연 추천·큐레이터 출처·사용자 기록의 순서를 바꾸지 않게 한다**는 것입니다. 신뢰가 제품의 출발점이므로 단기 매출을 위해 이 원칙을 훼손하면 사업 자체가 약해집니다.
|
||||
|
||||
첫 번째 수익원은 공개 탐색 화면의 **명시형 문맥 광고와 프로모션**입니다. 예를 들어 사용자가 공개된 식당·메뉴·상황 페이지에서 정보를 찾을 때, 해당 맥락에 맞는 행사·신메뉴·예약 가능 정보 등을 `광고` 또는 `프로모션`으로 명확히 구분해 노출합니다. 광고주는 의사결정을 앞둔 공개 독자에게 도달할 기회를 구매하고, 사용자는 광고와 큐레이터의 자연 언급을 혼동하지 않습니다. 이 모델은 충분한 공개 탐색 세션과 신뢰 기준이 생긴 뒤 소규모로 검증합니다.
|
||||
|
||||
두 번째는 식당·브랜드의 **투명한 캠페인 상품**입니다. 신메뉴, 지역 행사, 예약 가능 정보처럼 사용자의 의사결정에 실질적으로 도움이 되는 정보를 공개 페이지의 별도 영역에서 제공합니다. 유료 여부는 표기하고, 광고비가 검색·추천·공개 리뷰의 순위를 바꾸지 않게 운영합니다. 따라서 판매 단위는 "상위 노출 보장"이 아니라, 표기된 캠페인의 도달과 행동 결과입니다.
|
||||
|
||||
세 번째는 사용자가 거래를 원할 때만 연결하는 **예약·주문 제휴 수수료**입니다. Tasteby가 사용자를 수수료가 높은 식당으로 유도하지 않고, 사용자가 이미 고른 식당에서 예약·주문을 원할 때만 제휴 경로를 제공합니다. 이 수익원은 사용자 행동과 파트너 연동이 검증된 뒤 도입합니다.
|
||||
|
||||
추가로, 크리에이터가 자신의 출처·정정·아카이브 관리를 원한다면 공식 큐레이터 페이지와 관리 도구를 유료 또는 수익 분배 방식으로 검토할 수 있습니다. 다만 기존 콘텐츠를 단순 재포장해 과금하지 않고, 크리에이터와 시청자의 재탐색 문제를 실제로 줄이는 경우에만 추진합니다.
|
||||
|
||||
초기 12개월의 목표는 매출을 과장하는 것이 아니라, 출처 기반 탐색 → 후보 저장 → 재열람이 반복되는 공개 의사결정 문맥을 검증하는 것입니다. 그 증거가 생긴 뒤 광고·프로모션·제휴를 순서대로 시험해 신뢰를 지키며 매출을 만든다는 계획입니다.
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 아이디어 단계에 머물지 않고, 큐레이터 출처·식당·메뉴 탐색, 지도 기반 발견, 회원·찜·공개 리뷰·비공개 메모를 갖춘 MVP를 개발해 왔습니다. 서비스의 핵심은 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩과 검색을 통해 사용자가 큐레이터·지역·메뉴 기준으로 다시 찾게 하는 것입니다. 저는 Spring Boot와 Next.js를 중심으로 백엔드·프론트엔드·데이터 파이프라인·배포 환경을 직접 설계하고 구현해 왔습니다.
|
||||
|
||||
다음 단계의 사업화는 전국의 모든 맛집을 한꺼번에 늘리는 방식이 아닙니다. `큐레이터 1명 × 지역 1곳 × 메뉴 또는 식사 상황 1개`라는 작은 시장에서 출처 정확도와 실제 사용 행동을 먼저 증명하겠습니다.
|
||||
|
||||
**0~3개월**에는 첫 쐐기시장의 원본·식당·메뉴 데이터를 검수하고, 오류 정정 경로와 발견→원본 확인→후보 저장의 행동 계측을 갖추겠습니다. 식당 DB 5,000곳 이상과 등록 채널 10곳 이상은 단순 수량 목표가 아니라, 원본 출처와 메뉴 연결의 정확도를 통과한 데이터만 늘리는 품질 목표로 관리하겠습니다.
|
||||
|
||||
**4~6개월**에는 검색·커뮤니티·콘텐츠를 통해 이미 영상 속 식당을 찾는 사용자를 정확한 출처 페이지로 데려오겠습니다. 광고성 무차별 유입보다 "영상 속 그 집을 오늘의 후보로"라는 문제를 가진 사용자의 탐색·저장 행동을 검증하겠습니다. 동시에 큐레이터 또는 매니저에게는 단순 홍보 요청이 아니라, 오래된 콘텐츠의 출처 정리·정정·시청자 재탐색이라는 가치를 제안해 파트너십 3건을 목표로 협의하겠습니다.
|
||||
|
||||
**7~12개월**에는 한국의 검증 결과를 바탕으로 일본 여행 콘텐츠의 제한된 베타를 검토하고, 사용자가 찜한 후보를 동행과 함께 고를 수 있는 공유 기능을 도입하겠습니다. 목표 지표는 MAU 5만, B2B 식당·브랜드 캠페인 20건이지만, 이 수치는 단순 방문자 수가 아니라 출처 확인·후보 저장·재열람·공유 수신자의 탐색으로 검증하겠습니다. 첫 매출은 자연 추천과 분리된 공개 문맥 광고 또는 투명한 캠페인 상품에서 만들 계획입니다.
|
||||
|
||||
사업화의 핵심 위험은 기술보다 신뢰입니다. 따라서 원본 링크를 보존하고, 협찬·정정 상태를 관리하며, 비공개 메모를 광고 타기팅에 쓰지 않겠습니다. 저는 기술 개발, 데이터 품질, 사용자 경험, 초기 유통을 하나의 반복 실험으로 운영해 "더 많은 식당"이 아니라 "다시 쓰이는 신뢰"를 증명하겠습니다.
|
||||
|
||||
> 제출 전 사실 확인: `MVP 운영 중`, 실제 도메인 접속 상태, 현재 식당/채널 수는 제출일에 확인하여 위 첫 문단 또는 로드맵 표현을 조정한다.
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
저는 Tasteby의 제품과 기술 구현은 직접 추진해 왔지만, 다음 단계에서 필요한 것은 개발 조언보다 **신뢰를 훼손하지 않는 시장 진입과 계약의 기준**입니다. 책임멘토에게 네 가지 도움을 받고 싶습니다.
|
||||
|
||||
첫째, 크리에이터 파트너십의 실무입니다. Tasteby는 타인의 콘텐츠를 대신 소비시키는 서비스가 아니라 원본으로 다시 연결하는 서비스여야 합니다. 큐레이터·매니저에게 어떤 가치 제안을 해야 하는지, 출처·초상·인용·협찬 표기를 어떤 계약과 운영 절차로 정리해야 하는지 조언을 받고 싶습니다.
|
||||
|
||||
둘째, 초기 B2B 상품의 검증입니다. 식당이나 브랜드가 돈을 낸다고 해서 자연 추천 순위가 바뀌면 Tasteby의 차별점은 사라집니다. 공개 탐색 문맥에서 사용자가 받아들일 수 있는 광고·프로모션의 형태, 가격 이전에 검증해야 할 성과 지표, 첫 고객을 찾는 영업 경로를 함께 설계하고 싶습니다.
|
||||
|
||||
셋째, 초기 사용자 획득 전략입니다. 검색·커뮤니티·콘텐츠 중 어떤 좁은 시장에서 출처 탐색과 후보 저장이 실제로 반복되는지, 작은 예산으로 무엇을 먼저 검증해야 하는지에 대한 피드백이 필요합니다. '바이럴'이나 조회 수가 아니라 재방문과 결정 행동으로 판단하는 방법을 배우고 싶습니다.
|
||||
|
||||
넷째, 해외 확장 우선순위입니다. 일본 여행 콘텐츠는 분명한 사용 사례이지만, 국내에서 어떤 데이터 품질과 파트너십 기준을 먼저 증명해야 하는지, 다국어·현지 정보·권리 이슈를 어떤 순서로 풀어야 하는지 검토받고 싶습니다.
|
||||
|
||||
멘토링을 통해 막연한 인맥 소개보다, 파트너십·수익·유통에서 반복 가능한 의사결정 기준을 얻고 싶습니다. 이를 바탕으로 1인 개발자가 만든 MVP를 신뢰할 수 있는 소비자 서비스와 지속 가능한 사업으로 확장하겠습니다.
|
||||
|
||||
## Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. (선택 / 유튜브 링크만)
|
||||
|
||||
**권장: 제출한다.** 75~90초 분량으로 아래 흐름을 사용한다.
|
||||
|
||||
1. 0~15초 — "그 영상의 그 식당, 어디였지?"라는 개인 경험과 재검색 장면
|
||||
2. 15~40초 — Tasteby에서 큐레이터·식당·메뉴·원본을 연결해 찾는 실제 화면
|
||||
3. 40~60초 — 찜과 비공개 메모, 동행과 후보를 고르는 공유 카드의 가치
|
||||
4. 60~80초 — AI는 정보를 구조화하고, Tasteby는 사람의 신뢰를 다시 쓰게 한다는 차별점
|
||||
5. 80~90초 — 12개월 검증 목표와 멘토링 요청
|
||||
|
||||
> 제출 전 입력: `[YouTube URL]`
|
||||
> 제작 원칙: Tasteby 자체 화면·직접 제작한 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원을 무단 삽입하지 않는다.
|
||||
|
||||
## Q6. 사업 분야를 선택해주세요. (필수 / 드롭다운)
|
||||
|
||||
**제출 전 실제 선택지 확인 후 선택한다.**
|
||||
|
||||
1순위는 `AI·데이터`다. Tasteby의 사용자 가치는 외식 발견이지만, 영상·글에서 식당 정보를 구조화하고 출처 기반으로 탐색하게 하는 핵심 실행 수단이 AI·데이터이기 때문이다. 해당 선택지가 없으면 2순위는 `플랫폼/O2O`, 그다음은 `푸드테크`다. 예약·배달 거래가 현재 핵심이 아니므로 관광·여행은 일본 베타 이후의 보조 분야로 둔다.
|
||||
|
||||
## Q7. 지원자의 현재 창업 여부를 알려주세요. (필수 / 택1)
|
||||
|
||||
**법적 사실 확인 전 선택하지 않는다.**
|
||||
|
||||
| 확인 결과 | 선택 |
|
||||
|---|---|
|
||||
| 본인 명의 사업자/법인의 창업일이 기준 기간에 없거나, 기창업자 요건에 해당하지 않음 | `예비창업자` |
|
||||
| 창업일이 2019-08-21~2026-08-20이고 Tasteby가 기존 사업과 다른 이종 창업 아이템임 | `기창업자` |
|
||||
|
||||
MVP를 개발하거나 도메인을 운영했다는 사실만으로 Q7을 판단하지 않는다. 사업자등록·법인 설립·공고의 세부 기준을 제출 전에 확인한다.
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
**1차 원문/피드백 확보 후 제출할 답안이다. 현재는 아래 대괄호만 1차 사실로 교체한다.**
|
||||
|
||||
1차에서는 [1차에 제시한 핵심 문제와 해결 방식]을 중심으로 아이디어를 설명했습니다. 2차에서는 이를 단순한 맛집 정보 서비스가 아니라, `큐레이터 출처로 발견 → 개인 찜과 비공개 기록으로 재사용 → 선택한 후보를 동행과 공유`하는 제품 구조로 구체화했습니다.
|
||||
|
||||
또한 아이디어 수준의 설명에서 나아가, MVP에 구현한 출처·식당·메뉴 탐색과 찜·리뷰·메모 기능을 기준으로 사업화 순서를 다시 설계했습니다. 수익도 여러 가능성을 나열하는 대신, 공개 탐색 문맥의 명시형 광고·프로모션을 먼저 검증하고 예약·주문 제휴와 크리에이터 관리 도구는 조건이 충족될 때 단계적으로 검토하도록 정리했습니다.
|
||||
|
||||
마지막으로 2차에서는 기술 자체보다 신뢰를 핵심 경쟁력으로 명확히 했습니다. 원본 콘텐츠를 대체하지 않고 출처를 보존하며, 사용자의 비공개 메모를 광고 타기팅이나 외부 판매에 쓰지 않는 원칙을 세웠습니다. 이번 지원서는 "AI로 맛집을 모으겠다"는 설명에서 한 단계 더 나아가, 어떤 사용자가 왜 다시 쓰고 어떤 방식으로 사업이 되는지를 검증 가능한 계획으로 보완한 결과입니다.
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. (선택 / 2,000자)
|
||||
|
||||
Tasteby의 가장 큰 강점 중 하나는 아이디어를 설명하는 데서 멈추지 않고, 제품으로 만들고 운영 가능한 형태로 옮겨 왔다는 점입니다. 저는 1인 풀스택 개발자로서 문제 정의부터 데이터 구조, 백엔드·프론트엔드 구현, AI 처리 파이프라인, 배포 환경까지 직접 설계하고 연결해 왔습니다.
|
||||
|
||||
Tasteby에서는 Spring Boot와 Java 기반의 서비스 로직, Next.js 기반의 사용자 화면, Oracle 23ai 벡터 데이터베이스와 Redis를 활용한 데이터 처리 구조를 구성했습니다. 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩·지도·검색으로 사용자가 다시 찾을 수 있게 만드는 파이프라인도 직접 만들었습니다. 기술을 개별 기능으로 쌓기보다, "출처를 찾는다 → 후보를 저장한다 → 방문 뒤 기억한다 → 다음 선택에 다시 쓴다"는 한 사용 흐름이 완성되도록 설계한 경험이 있습니다.
|
||||
|
||||
저의 실행 방식은 작은 가설을 빠르게 제품으로 옮기고, 실제 사용 행동으로 다음 우선순위를 정하는 것입니다. 예를 들어 Tasteby의 비공개 메모는 리뷰를 많이 받기 위한 기능이 아니라, 사용자가 좋았던 경험을 다음 외식에 다시 쓰게 하기 위한 기능입니다. 찜 공유 역시 전체 취향을 공개하는 기능이 아니라, 사용자가 고른 후보만 동행과 함께 결정하게 하는 기능으로 분리했습니다. 이처럼 기술의 가능성보다 사용자의 신뢰와 권한을 먼저 설계하는 것이 저의 제품 역량입니다.
|
||||
|
||||
또한 혼자서도 기획·개발·운영을 연결할 수 있지만, 모든 것을 혼자 해결하려 하지 않습니다. 크리에이터 계약, 저작권·표기, 초기 B2B 영업, 해외 확장은 멘토와 파트너의 전문성이 필요한 영역으로 분명히 인식하고 있습니다. 저는 빠르게 만들 수 있는 실행력과, 모르는 영역을 검증 가능한 질문으로 바꾸는 운영 방식을 바탕으로 Tasteby를 사업으로 성장시키겠습니다.
|
||||
|
||||
> 제출 전 보강 후보: 공개 가능한 직장 경력, 이전 프로젝트, 수상·자격, 서비스 운영 수치가 있으면 사실 확인 뒤 한 단락만 추가한다.
|
||||
|
||||
## Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. (선택 / 드롭다운)
|
||||
|
||||
`팀원 없음`
|
||||
|
||||
현재는 1인 창업자로 제품을 직접 개발·운영한다. 다만 법무·크리에이터 파트너십·B2B 영업은 외부 전문가 및 멘토와 보완할 계획이다.
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개 + 좋아요)
|
||||
|
||||
> **맛집 영상을 보다가 "그 집 어디였지?"를 되묻는 사람을 위해 만들었습니다.**
|
||||
> Tasteby는 신뢰하는 미식 큐레이터가 언급한 식당과 메뉴를 원본 출처와 함께 찾고, 마음에 드는 곳은 내 찜에 남겨 다음 식사에 다시 쓰게 합니다.
|
||||
> 좋은 한 끼를 발견하는 순간과, 좋았던 한 끼를 기억하는 순간을 연결합니다.
|
||||
> `www.tasteby.net`
|
||||
|
||||
> 게시 전: 실제 접속 URL과 대표 스크린샷을 확인한다.
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
제출 직전에 아래를 각각 읽고 동의한다.
|
||||
|
||||
- 참여 서약서
|
||||
- 본인 아이디어 확인 서약서
|
||||
- 비밀유지 서약서
|
||||
|
||||
## 사진 배분 계획 (전체 10장 제한)
|
||||
|
||||
| 문항 | 장수 | 권장 이미지 | 심사에서 보여 줄 사실 |
|
||||
|------|---:|---|---|
|
||||
| Q2 | 1 | 직접 만든 `영상 속 정보 → Tasteby 출처·지도 → 다음 식사` 흐름 도식 | 왜 이 서비스가 필요한가 |
|
||||
| Q3-1 | 3 | 지도 탐색, 식당 상세의 원본/메뉴 근거, 찜·비공개 메모 화면 | 출처·개인 기록의 차별점 |
|
||||
| Q4-1 | 2 | 데이터 처리·정정 흐름 도식, 12개월 로드맵 | 이미 만든 것과 다음 검증 순서 |
|
||||
| Q9 | 1 | 실제 서비스 아키텍처 또는 개발·배포 흐름 | 1인 실행 역량 |
|
||||
| Q11 | 1 | 모바일 또는 데스크톱 대표 화면 한 장 | 공개 소개의 첫 인상 |
|
||||
| 예비 | 2 | 수신자 공유 카드, 모바일 탐색 화면 | 심사 코멘트 대응 또는 품질이 높은 화면 교체 |
|
||||
|
||||
총 8장을 기본으로 사용하고 2장은 예비로 남긴다. 모든 화면은 제출일 기준 실제 동작·표현과 일치해야 하며, 원본 영상 캡처·타인 음식 사진은 사용권을 확인하지 못하면 사용하지 않는다.
|
||||
180
docs/ir/modu-startup-2026-09/v3.md
Normal file
180
docs/ir/modu-startup-2026-09/v3.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# 모두의 창업 2차 지원서 — v3
|
||||
|
||||
> 작성일: 2026-09-15
|
||||
> 상태: v2에 **실측 지표**를 반영한 판. `제출 전 확정` 표기 항목은 사실 확인 뒤에만 확정한다.
|
||||
|
||||
## v2 → v3 변경 요약
|
||||
- **Q4-1 전면 수정**: "3개월에 식당 5,000곳"(현재의 10배, 달성 불가) → 현재 실측치(채널 6·영상 909·식당 500)에서 출발하는 배수 목표로 교체. 0~3개월 과제를 수량이 아니라 **LLM 미검증 1,071건 정리**로 재정의
|
||||
- **Q4-1에 사용자 현황 명시**: 공개 회원 모집을 아직 시작하지 않은 단계임을 밝히고, 4~6개월의 핵심 과제를 첫 사용자 집단 확보로 지정
|
||||
- **Q3-1·Q4-1에 해외 데이터 반영**: 일본 28곳 포함 해외 60여 곳이 이미 축적됨 → 일본 확장이 "구상"이 아니라 "이미 시작된 축적"임을 근거로 제시
|
||||
- **깨진 참조 링크 3개 제거** (`docs/design/705-…`, `docs/strategy/…`, `docs/design/711-…` — 리포에 존재하지 않음)
|
||||
|
||||
> 실측 출처: 2026-09-15 Admin 화면 및 `GET /api/restaurants?limit=100000` 조회. 상세는 `README.md` 실측 지표 표.
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 10~100자)
|
||||
|
||||
> 신뢰하는 미식 큐레이터의 영상 속 맛집을 찾아, 나의 다음 식사와 기록으로 연결하는 Tasteby
|
||||
|
||||
- v2 검증: 54자. 제출 화면의 실제 글자 수를 최종 확인한다.
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
저는 맛집 영상을 보는 것을 좋아하지만, 막상 식사 약속이 잡히면 같은 문제를 반복해서 겪었습니다. "성시경 영상에서 본 그 국밥집이 어디였지?" 기억나는 것은 사람과 메뉴의 인상뿐이었습니다. 다시 영상을 찾아 자막을 넘기고, 식당 이름을 받아 적어 지도에 옮겨야 했습니다. 좋아하는 채널이 늘수록 저장한 정보도 늘었지만, 정작 필요한 순간에는 더 찾기 어려워졌습니다.
|
||||
|
||||
이 불편은 일본 여행에서 더 선명해졌습니다. 여행 전에 한국 미식 유튜버의 일본 맛집 영상을 여러 편 봤지만, 현지에서는 어느 영상의 어느 장면에 나온 식당인지 다시 찾는 데 시간이 들었습니다. 별점과 후기 수가 많은 식당은 쉽게 찾을 수 있었지만, 제가 실제로 궁금했던 것은 "내가 신뢰하는 이 사람이 왜 이곳을 골랐는가"였습니다. 영상, 지도, 메모앱이 각각 답의 일부만 갖고 있었습니다.
|
||||
|
||||
그래서 출발한 질문은 "맛집을 더 많이 모으려면 어떻게 해야 할까?"가 아니었습니다. **신뢰하는 사람의 선택을, 다음 식사를 고를 때 다시 쓸 수 있게 하려면 어떻게 해야 할까?**였습니다.
|
||||
|
||||
Tasteby는 미식 큐레이터의 영상·글 속 식당, 메뉴, 언급 맥락을 구조화해 지도와 탐색 화면에서 찾게 하는 서비스입니다. 사용자는 원본 콘텐츠로 다시 돌아가 맥락을 확인할 수 있고, 마음에 드는 곳은 자신의 찜과 비공개 메모에 남길 수 있습니다. 즉, Tasteby는 원본 영상을 대체하거나 익명 다수의 평가를 더 크게 만드는 서비스가 아니라, 흩어진 신뢰의 단서를 실제 외식 결정에 쓸 수 있게 연결하는 도구입니다.
|
||||
|
||||
AI는 이 일을 가능하게 하는 수단입니다. 영상 자막과 공개 정보를 바탕으로 식당 후보를 구조화하되, 원본 출처를 남기고 오류는 정정할 수 있게 설계합니다. 저는 "AI가 맛집을 대신 추천한다"보다 "사람이 쌓아 온 신뢰를 사용자가 다시 쓸 수 있게 한다"는 방향이 더 오래 갈 수 있다고 믿습니다. Tasteby는 좋은 한 끼를 찾는 순간과, 좋았던 한 끼를 다시 기억하는 순간을 하나의 경험으로 만들고자 합니다.
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 또 하나의 맛집 순위 서비스가 아닙니다. 출발점이 "평점이 높은 곳은 어디인가?"가 아니라 **"내가 신뢰하는 사람이 어느 콘텐츠에서, 어떤 메뉴를, 왜 언급했는가?"**이기 때문입니다.
|
||||
|
||||
기존 맛집 서비스는 대체로 다수 이용자의 별점·후기, 예약 가능 여부, 지역 검색을 중심으로 설계돼 있습니다. 이 방식은 넓은 선택지를 빠르게 보여 주는 데 유용하지만, 영상을 보고 특정 사람의 선택을 기억한 사용자에게는 두 가지 공백이 남습니다. 첫째, 영상 속 식당의 이름·주소·메뉴가 콘텐츠 안에 흩어져 있어 나중에 다시 찾기 어렵습니다. 둘째, 평균 별점만으로는 왜 그 사람이 그 식당을 언급했는지, 내가 오늘 갈 이유가 있는지 판단하기 어렵습니다.
|
||||
|
||||
Tasteby의 차별점은 세 가지입니다.
|
||||
|
||||
첫째, **출처가 있는 발견**입니다. 식당을 보여 줄 때 원본 콘텐츠와 메뉴·언급 맥락을 함께 연결합니다. 사용자는 Tasteby의 요약만 믿을 필요 없이 원본으로 돌아가 확인할 수 있습니다. 추천인지 단순 언급인지, 협찬 또는 정정 정보가 확인되는 경우에는 이를 구분해 보이는 방향으로 신뢰를 설계합니다.
|
||||
|
||||
둘째, **분야별 큐레이터의 선택을 탐색 기준으로 사용**합니다. 사용자는 무작위 목록이 아니라 자신이 신뢰하는 미식 큐레이터, 먹고 싶은 메뉴, 갈 지역을 함께 놓고 후보를 좁힐 수 있습니다. 이는 "유명해서"가 아니라 특정 음식과 상황을 꾸준히 다뤄 온 사람의 관점을 발견의 출발점으로 삼는 방식입니다.
|
||||
|
||||
셋째, **개인의 맛 기억을 기본 비공개로 보존**합니다. 사용자는 방문 뒤 좋았던 이유와 다음에 갈 조건을 자기 메모로 남길 수 있습니다. 공개 리뷰를 많이 쓰게 하는 대신, 먼저 나를 위한 기록이 다음 선택에 다시 쓰이도록 하는 것이 목표입니다. 나중에 사용자가 원할 때만 일부 후보를 동행에게 공유할 수 있으며, 비공개 메모는 공유되지 않습니다.
|
||||
|
||||
이 구조는 국내에만 적용되는 것이 아닙니다. 현재도 한국 큐레이터가 다룬 일본·미국·싱가포르 등 해외 식당 60여 곳이 같은 방식으로 쌓이고 있습니다. 여행지에서 익명 리뷰를 처음부터 다시 읽는 대신, 이미 신뢰하는 사람의 선택을 그대로 꺼내 쓸 수 있다는 뜻입니다.
|
||||
|
||||
Tasteby가 해결하려는 문제는 정보 부족이 아니라 **신뢰할 만한 정보를 다시 쓸 수 없는 문제**입니다. 음식 콘텐츠를 보는 사람은 다음 식사를 더 쉽게 결정하고, 크리에이터는 자신의 콘텐츠가 일회성 조회를 넘어 정정 가능하고 탐색 가능한 아카이브로 이어질 수 있습니다. AI는 이 구조를 빠르게 만들지만, 경쟁력의 핵심은 AI 자체가 아니라 출처를 보존하고 개인의 선택으로 이어 주는 제품 경험입니다.
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
Tasteby의 수익 원칙은 분명합니다. **사용자의 비공개 찜과 메모를 판매하지 않고, 돈을 낸 식당이 자연 추천·큐레이터 출처·사용자 기록의 순서를 바꾸지 않게 한다**는 것입니다. 신뢰가 제품의 출발점이므로 단기 매출을 위해 이 원칙을 훼손하면 사업 자체가 약해집니다.
|
||||
|
||||
첫 번째 수익원은 공개 탐색 화면의 **명시형 문맥 광고와 프로모션**입니다. 예를 들어 사용자가 공개된 식당·메뉴·상황 페이지에서 정보를 찾을 때, 해당 맥락에 맞는 행사·신메뉴·예약 가능 정보 등을 `광고` 또는 `프로모션`으로 명확히 구분해 노출합니다. 광고주는 의사결정을 앞둔 공개 독자에게 도달할 기회를 구매하고, 사용자는 광고와 큐레이터의 자연 언급을 혼동하지 않습니다. 이 모델은 충분한 공개 탐색 세션과 신뢰 기준이 생긴 뒤 소규모로 검증합니다.
|
||||
|
||||
두 번째는 식당·브랜드의 **투명한 캠페인 상품**입니다. 신메뉴, 지역 행사, 예약 가능 정보처럼 사용자의 의사결정에 실질적으로 도움이 되는 정보를 공개 페이지의 별도 영역에서 제공합니다. 유료 여부는 표기하고, 광고비가 검색·추천·공개 리뷰의 순위를 바꾸지 않게 운영합니다. 따라서 판매 단위는 "상위 노출 보장"이 아니라, 표기된 캠페인의 도달과 행동 결과입니다.
|
||||
|
||||
세 번째는 사용자가 거래를 원할 때만 연결하는 **예약·주문 제휴 수수료**입니다. Tasteby가 사용자를 수수료가 높은 식당으로 유도하지 않고, 사용자가 이미 고른 식당에서 예약·주문을 원할 때만 제휴 경로를 제공합니다. 이 수익원은 사용자 행동과 파트너 연동이 검증된 뒤 도입합니다.
|
||||
|
||||
추가로, 크리에이터가 자신의 출처·정정·아카이브 관리를 원한다면 공식 큐레이터 페이지와 관리 도구를 유료 또는 수익 분배 방식으로 검토할 수 있습니다. 다만 기존 콘텐츠를 단순 재포장해 과금하지 않고, 크리에이터와 시청자의 재탐색 문제를 실제로 줄이는 경우에만 추진합니다.
|
||||
|
||||
초기 12개월의 목표는 매출을 과장하는 것이 아니라, 출처 기반 탐색 → 후보 저장 → 재열람이 반복되는 공개 의사결정 문맥을 검증하는 것입니다. 그 증거가 생긴 뒤 광고·프로모션·제휴를 순서대로 시험해 신뢰를 지키며 매출을 만든다는 계획입니다.
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 아이디어 단계에 머물지 않고, 큐레이터 출처·식당·메뉴 탐색, 지도 기반 발견, 회원·찜·공개 리뷰·비공개 메모를 갖춘 서비스를 직접 개발해 운영하고 있습니다. 2026년 9월 기준 등록 채널 6곳, 수집 영상 909편에서 추출해 좌표까지 연결한 식당 500곳을 확보했고, 그중에는 일본 28곳을 포함한 해외 식당 60여 곳이 이미 포함돼 있습니다. 저는 Spring Boot와 Next.js를 중심으로 백엔드·프론트엔드·데이터 파이프라인·배포 환경을 직접 설계하고 구현했습니다.
|
||||
|
||||
다음 단계의 사업화는 전국의 모든 맛집을 한꺼번에 늘리는 방식이 아닙니다. `큐레이터 1명 × 지역 1곳 × 메뉴 또는 식사 상황 1개`라는 작은 시장에서 출처 정확도와 실제 사용 행동을 먼저 증명하겠습니다.
|
||||
|
||||
**0~3개월에는 수량보다 신뢰도를 먼저 올리겠습니다.** 현재 LLM 검증을 거치지 않은 영상-식당 연결이 1,071건 남아 있습니다. 이를 정리해 출처와 메뉴 연결이 검증된 데이터만 노출하고, 오류 정정 경로와 `발견 → 원본 확인 → 후보 저장`의 행동 계측을 갖추겠습니다. 데이터는 채널을 10곳으로 늘려 식당 1,500곳 규모를 목표로 하되, 정확도 기준을 통과한 것만 셈에 넣겠습니다.
|
||||
|
||||
**4~6개월에는 첫 사용자 집단을 만들겠습니다.** 현재는 공개 회원 모집을 시작하지 않았고 제품과 데이터 품질을 먼저 확보하는 단계입니다. 따라서 이 구간의 핵심 과제는 방문자 수를 늘리는 것이 아니라, "영상 속 그 집을 오늘의 후보로"라는 문제를 이미 가진 사용자를 검색·커뮤니티·콘텐츠를 통해 정확한 출처 페이지로 데려와 탐색과 저장이 반복되는지 확인하는 것입니다. 동시에 큐레이터 또는 매니저에게 단순 홍보 요청이 아니라 오래된 콘텐츠의 출처 정리·정정·시청자 재탐색이라는 가치를 제안해 파트너십 3건을 협의하겠습니다.
|
||||
|
||||
**7~12개월에는 검증 결과를 확장하겠습니다.** 이미 확보한 일본 28곳은 한국 큐레이터가 현지에서 남긴 기록이므로, 새로운 데이터 수집 없이도 여행 사용 맥락을 검증할 출발점이 됩니다. 여기에 사용자가 찜한 후보를 동행과 함께 고르는 공유 기능을 더하겠습니다. 목표는 MAU 5만과 B2B 캠페인 20건이지만, 이 수치는 단순 방문자 수가 아니라 출처 확인·후보 저장·재열람·공유 수신자의 탐색으로 검증하겠습니다. 첫 매출은 자연 추천과 분리된 공개 문맥 광고 또는 투명한 캠페인 상품에서 만들 계획입니다.
|
||||
|
||||
사업화의 핵심 위험은 기술보다 신뢰입니다. 따라서 원본 링크를 보존하고, 협찬·정정 상태를 관리하며, 비공개 메모를 광고 타기팅에 쓰지 않겠습니다. 저는 "더 많은 식당"이 아니라 "다시 쓰이는 신뢰"를 증명하겠습니다.
|
||||
|
||||
> 제출 전 사실 확인: 위 실측치(채널 6·영상 909·식당 500·미검증 1,071·해외 60여)는 2026-09-15 기준이다. 제출일에 다시 조회해 갱신한다.
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
저는 Tasteby의 제품과 기술 구현은 직접 추진해 왔지만, 다음 단계에서 필요한 것은 개발 조언보다 **신뢰를 훼손하지 않는 시장 진입과 계약의 기준**입니다. 책임멘토에게 네 가지 도움을 받고 싶습니다.
|
||||
|
||||
첫째, 크리에이터 파트너십의 실무입니다. Tasteby는 타인의 콘텐츠를 대신 소비시키는 서비스가 아니라 원본으로 다시 연결하는 서비스여야 합니다. 큐레이터·매니저에게 어떤 가치 제안을 해야 하는지, 출처·초상·인용·협찬 표기를 어떤 계약과 운영 절차로 정리해야 하는지 조언을 받고 싶습니다.
|
||||
|
||||
둘째, 초기 B2B 상품의 검증입니다. 식당이나 브랜드가 돈을 낸다고 해서 자연 추천 순위가 바뀌면 Tasteby의 차별점은 사라집니다. 공개 탐색 문맥에서 사용자가 받아들일 수 있는 광고·프로모션의 형태, 가격 이전에 검증해야 할 성과 지표, 첫 고객을 찾는 영업 경로를 함께 설계하고 싶습니다.
|
||||
|
||||
셋째, 초기 사용자 획득 전략입니다. 검색·커뮤니티·콘텐츠 중 어떤 좁은 시장에서 출처 탐색과 후보 저장이 실제로 반복되는지, 작은 예산으로 무엇을 먼저 검증해야 하는지에 대한 피드백이 필요합니다. '바이럴'이나 조회 수가 아니라 재방문과 결정 행동으로 판단하는 방법을 배우고 싶습니다.
|
||||
|
||||
넷째, 해외 확장 우선순위입니다. 일본 여행 콘텐츠는 분명한 사용 사례이지만, 국내에서 어떤 데이터 품질과 파트너십 기준을 먼저 증명해야 하는지, 다국어·현지 정보·권리 이슈를 어떤 순서로 풀어야 하는지 검토받고 싶습니다.
|
||||
|
||||
멘토링을 통해 막연한 인맥 소개보다, 파트너십·수익·유통에서 반복 가능한 의사결정 기준을 얻고 싶습니다. 이를 바탕으로 1인 개발자가 만든 MVP를 신뢰할 수 있는 소비자 서비스와 지속 가능한 사업으로 확장하겠습니다.
|
||||
|
||||
## Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. (선택 / 유튜브 링크만)
|
||||
|
||||
**권장: 제출한다.** 75~90초 분량으로 아래 흐름을 사용한다.
|
||||
|
||||
1. 0~15초 — "그 영상의 그 식당, 어디였지?"라는 개인 경험과 재검색 장면
|
||||
2. 15~40초 — Tasteby에서 큐레이터·식당·메뉴·원본을 연결해 찾는 실제 화면
|
||||
3. 40~60초 — 찜과 비공개 메모, 동행과 후보를 고르는 공유 카드의 가치
|
||||
4. 60~80초 — AI는 정보를 구조화하고, Tasteby는 사람의 신뢰를 다시 쓰게 한다는 차별점
|
||||
5. 80~90초 — 12개월 검증 목표와 멘토링 요청
|
||||
|
||||
> 제출 전 입력: `[YouTube URL]`
|
||||
> 제작 원칙: Tasteby 자체 화면·직접 제작한 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원을 무단 삽입하지 않는다.
|
||||
|
||||
## Q6. 사업 분야를 선택해주세요. (필수 / 드롭다운)
|
||||
|
||||
**제출 전 실제 선택지 확인 후 선택한다.**
|
||||
|
||||
1순위는 `AI·데이터`다. Tasteby의 사용자 가치는 외식 발견이지만, 영상·글에서 식당 정보를 구조화하고 출처 기반으로 탐색하게 하는 핵심 실행 수단이 AI·데이터이기 때문이다. 해당 선택지가 없으면 2순위는 `플랫폼/O2O`, 그다음은 `푸드테크`다. 예약·배달 거래가 현재 핵심이 아니므로 관광·여행은 일본 베타 이후의 보조 분야로 둔다.
|
||||
|
||||
## Q7. 지원자의 현재 창업 여부를 알려주세요. (필수 / 택1)
|
||||
|
||||
**법적 사실 확인 전 선택하지 않는다.**
|
||||
|
||||
| 확인 결과 | 선택 |
|
||||
|---|---|
|
||||
| 본인 명의 사업자/법인의 창업일이 기준 기간에 없거나, 기창업자 요건에 해당하지 않음 | `예비창업자` |
|
||||
| 창업일이 2019-08-21~2026-08-20이고 Tasteby가 기존 사업과 다른 이종 창업 아이템임 | `기창업자` |
|
||||
|
||||
MVP를 개발하거나 도메인을 운영했다는 사실만으로 Q7을 판단하지 않는다. 사업자등록·법인 설립·공고의 세부 기준을 제출 전에 확인한다.
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
**1차 원문/피드백 확보 후 제출할 답안이다. 현재는 아래 대괄호만 1차 사실로 교체한다.**
|
||||
|
||||
1차에서는 [1차에 제시한 핵심 문제와 해결 방식]을 중심으로 아이디어를 설명했습니다. 2차에서는 이를 단순한 맛집 정보 서비스가 아니라, `큐레이터 출처로 발견 → 개인 찜과 비공개 기록으로 재사용 → 선택한 후보를 동행과 공유`하는 제품 구조로 구체화했습니다.
|
||||
|
||||
또한 아이디어 수준의 설명에서 나아가, MVP에 구현한 출처·식당·메뉴 탐색과 찜·리뷰·메모 기능을 기준으로 사업화 순서를 다시 설계했습니다. 수익도 여러 가능성을 나열하는 대신, 공개 탐색 문맥의 명시형 광고·프로모션을 먼저 검증하고 예약·주문 제휴와 크리에이터 관리 도구는 조건이 충족될 때 단계적으로 검토하도록 정리했습니다.
|
||||
|
||||
마지막으로 2차에서는 기술 자체보다 신뢰를 핵심 경쟁력으로 명확히 했습니다. 원본 콘텐츠를 대체하지 않고 출처를 보존하며, 사용자의 비공개 메모를 광고 타기팅이나 외부 판매에 쓰지 않는 원칙을 세웠습니다. 이번 지원서는 "AI로 맛집을 모으겠다"는 설명에서 한 단계 더 나아가, 어떤 사용자가 왜 다시 쓰고 어떤 방식으로 사업이 되는지를 검증 가능한 계획으로 보완한 결과입니다.
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. (선택 / 2,000자)
|
||||
|
||||
Tasteby의 가장 큰 강점 중 하나는 아이디어를 설명하는 데서 멈추지 않고, 제품으로 만들고 운영 가능한 형태로 옮겨 왔다는 점입니다. 저는 1인 풀스택 개발자로서 문제 정의부터 데이터 구조, 백엔드·프론트엔드 구현, AI 처리 파이프라인, 배포 환경까지 직접 설계하고 연결해 왔습니다.
|
||||
|
||||
Tasteby에서는 Spring Boot와 Java 기반의 서비스 로직, Next.js 기반의 사용자 화면, Oracle 23ai 벡터 데이터베이스와 Redis를 활용한 데이터 처리 구조를 구성했습니다. 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩·지도·검색으로 사용자가 다시 찾을 수 있게 만드는 파이프라인도 직접 만들었습니다. 기술을 개별 기능으로 쌓기보다, "출처를 찾는다 → 후보를 저장한다 → 방문 뒤 기억한다 → 다음 선택에 다시 쓴다"는 한 사용 흐름이 완성되도록 설계한 경험이 있습니다.
|
||||
|
||||
저의 실행 방식은 작은 가설을 빠르게 제품으로 옮기고, 실제 사용 행동으로 다음 우선순위를 정하는 것입니다. 예를 들어 Tasteby의 비공개 메모는 리뷰를 많이 받기 위한 기능이 아니라, 사용자가 좋았던 경험을 다음 외식에 다시 쓰게 하기 위한 기능입니다. 찜 공유 역시 전체 취향을 공개하는 기능이 아니라, 사용자가 고른 후보만 동행과 함께 결정하게 하는 기능으로 분리했습니다. 이처럼 기술의 가능성보다 사용자의 신뢰와 권한을 먼저 설계하는 것이 저의 제품 역량입니다.
|
||||
|
||||
또한 혼자서도 기획·개발·운영을 연결할 수 있지만, 모든 것을 혼자 해결하려 하지 않습니다. 크리에이터 계약, 저작권·표기, 초기 B2B 영업, 해외 확장은 멘토와 파트너의 전문성이 필요한 영역으로 분명히 인식하고 있습니다. 저는 빠르게 만들 수 있는 실행력과, 모르는 영역을 검증 가능한 질문으로 바꾸는 운영 방식을 바탕으로 Tasteby를 사업으로 성장시키겠습니다.
|
||||
|
||||
> 제출 전 보강 후보: 공개 가능한 직장 경력, 이전 프로젝트, 수상·자격, 서비스 운영 수치가 있으면 사실 확인 뒤 한 단락만 추가한다.
|
||||
|
||||
## Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. (선택 / 드롭다운)
|
||||
|
||||
`팀원 없음`
|
||||
|
||||
현재는 1인 창업자로 제품을 직접 개발·운영한다. 다만 법무·크리에이터 파트너십·B2B 영업은 외부 전문가 및 멘토와 보완할 계획이다.
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개 + 좋아요)
|
||||
|
||||
> **맛집 영상을 보다가 "그 집 어디였지?"를 되묻는 사람을 위해 만들었습니다.**
|
||||
> Tasteby는 신뢰하는 미식 큐레이터가 언급한 식당과 메뉴를 원본 출처와 함께 찾고, 마음에 드는 곳은 내 찜에 남겨 다음 식사에 다시 쓰게 합니다.
|
||||
> 좋은 한 끼를 발견하는 순간과, 좋았던 한 끼를 기억하는 순간을 연결합니다.
|
||||
> `www.tasteby.net`
|
||||
|
||||
> 게시 전: 실제 접속 URL과 대표 스크린샷을 확인한다.
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
제출 직전에 아래를 각각 읽고 동의한다.
|
||||
|
||||
- 참여 서약서
|
||||
- 본인 아이디어 확인 서약서
|
||||
- 비밀유지 서약서
|
||||
|
||||
## 사진 배분 계획 (전체 10장 제한)
|
||||
|
||||
| 문항 | 장수 | 권장 이미지 | 심사에서 보여 줄 사실 |
|
||||
|------|---:|---|---|
|
||||
| Q2 | 1 | 직접 만든 `영상 속 정보 → Tasteby 출처·지도 → 다음 식사` 흐름 도식 | 왜 이 서비스가 필요한가 |
|
||||
| Q3-1 | 3 | 지도 탐색, 식당 상세의 원본/메뉴 근거, 찜·비공개 메모 화면 | 출처·개인 기록의 차별점 |
|
||||
| Q4-1 | 2 | 데이터 처리·정정 흐름 도식, 12개월 로드맵 | 이미 만든 것과 다음 검증 순서 |
|
||||
| Q9 | 1 | 실제 서비스 아키텍처 또는 개발·배포 흐름 | 1인 실행 역량 |
|
||||
| Q11 | 1 | 모바일 또는 데스크톱 대표 화면 한 장 | 공개 소개의 첫 인상 |
|
||||
| 예비 | 2 | 수신자 공유 카드, 모바일 탐색 화면 | 심사 코멘트 대응 또는 품질이 높은 화면 교체 |
|
||||
|
||||
총 8장을 기본으로 사용하고 2장은 예비로 남긴다. 모든 화면은 제출일 기준 실제 동작·표현과 일치해야 하며, 원본 영상 캡처·타인 음식 사진은 사용권을 확인하지 못하면 사용하지 않는다.
|
||||
187
docs/ir/modu-startup-2026-09/v4.md
Normal file
187
docs/ir/modu-startup-2026-09/v4.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 모두의 창업 2차 지원서 — v4
|
||||
|
||||
> 작성일: 2026-09-15
|
||||
> 상태: Q8(재도전 가점)까지 채운 판. `제출 전 확정` 표기 항목만 사실 확인 뒤 확정한다.
|
||||
|
||||
## v3 → v4 변경 요약
|
||||
- **Q8 완성**: 1차 지원서 원문이 `v1.md`(사용자 제공 원고)임을 확인 → 대괄호를 실제 1차 내용으로 채움. 1차의 실제 약점 4가지(제품 정의·수익모델 나열·근거 없는 수치·멘토 문항 오답)와 2차의 수정을 1:1로 대응시킴
|
||||
|
||||
## v2 → v3 변경 요약
|
||||
- **Q4-1 전면 수정**: "3개월에 식당 5,000곳"(현재의 10배, 달성 불가) → 현재 실측치(채널 6·영상 909·식당 500)에서 출발하는 배수 목표로 교체. 0~3개월 과제를 수량이 아니라 **LLM 미검증 1,071건 정리**로 재정의
|
||||
- **Q4-1에 사용자 현황 명시**: 공개 회원 모집을 아직 시작하지 않은 단계임을 밝히고, 4~6개월의 핵심 과제를 첫 사용자 집단 확보로 지정
|
||||
- **Q3-1·Q4-1에 해외 데이터 반영**: 일본 28곳 포함 해외 60여 곳이 이미 축적됨 → 일본 확장이 "구상"이 아니라 "이미 시작된 축적"임을 근거로 제시
|
||||
- **깨진 참조 링크 3개 제거** (`docs/design/705-…`, `docs/strategy/…`, `docs/design/711-…` — 리포에 존재하지 않음)
|
||||
|
||||
> 실측 출처: 2026-09-15 Admin 화면 및 `GET /api/restaurants?limit=100000` 조회. 상세는 `README.md` 실측 지표 표.
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 10~100자)
|
||||
|
||||
> 신뢰하는 미식 큐레이터의 영상 속 맛집을 찾아, 나의 다음 식사와 기록으로 연결하는 Tasteby
|
||||
|
||||
- v2 검증: 54자. 제출 화면의 실제 글자 수를 최종 확인한다.
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
저는 맛집 영상을 보는 것을 좋아하지만, 막상 식사 약속이 잡히면 같은 문제를 반복해서 겪었습니다. "성시경 영상에서 본 그 국밥집이 어디였지?" 기억나는 것은 사람과 메뉴의 인상뿐이었습니다. 다시 영상을 찾아 자막을 넘기고, 식당 이름을 받아 적어 지도에 옮겨야 했습니다. 좋아하는 채널이 늘수록 저장한 정보도 늘었지만, 정작 필요한 순간에는 더 찾기 어려워졌습니다.
|
||||
|
||||
이 불편은 일본 여행에서 더 선명해졌습니다. 여행 전에 한국 미식 유튜버의 일본 맛집 영상을 여러 편 봤지만, 현지에서는 어느 영상의 어느 장면에 나온 식당인지 다시 찾는 데 시간이 들었습니다. 별점과 후기 수가 많은 식당은 쉽게 찾을 수 있었지만, 제가 실제로 궁금했던 것은 "내가 신뢰하는 이 사람이 왜 이곳을 골랐는가"였습니다. 영상, 지도, 메모앱이 각각 답의 일부만 갖고 있었습니다.
|
||||
|
||||
그래서 출발한 질문은 "맛집을 더 많이 모으려면 어떻게 해야 할까?"가 아니었습니다. **신뢰하는 사람의 선택을, 다음 식사를 고를 때 다시 쓸 수 있게 하려면 어떻게 해야 할까?**였습니다.
|
||||
|
||||
Tasteby는 미식 큐레이터의 영상·글 속 식당, 메뉴, 언급 맥락을 구조화해 지도와 탐색 화면에서 찾게 하는 서비스입니다. 사용자는 원본 콘텐츠로 다시 돌아가 맥락을 확인할 수 있고, 마음에 드는 곳은 자신의 찜과 비공개 메모에 남길 수 있습니다. 즉, Tasteby는 원본 영상을 대체하거나 익명 다수의 평가를 더 크게 만드는 서비스가 아니라, 흩어진 신뢰의 단서를 실제 외식 결정에 쓸 수 있게 연결하는 도구입니다.
|
||||
|
||||
AI는 이 일을 가능하게 하는 수단입니다. 영상 자막과 공개 정보를 바탕으로 식당 후보를 구조화하되, 원본 출처를 남기고 오류는 정정할 수 있게 설계합니다. 저는 "AI가 맛집을 대신 추천한다"보다 "사람이 쌓아 온 신뢰를 사용자가 다시 쓸 수 있게 한다"는 방향이 더 오래 갈 수 있다고 믿습니다. Tasteby는 좋은 한 끼를 찾는 순간과, 좋았던 한 끼를 다시 기억하는 순간을 하나의 경험으로 만들고자 합니다.
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 또 하나의 맛집 순위 서비스가 아닙니다. 출발점이 "평점이 높은 곳은 어디인가?"가 아니라 **"내가 신뢰하는 사람이 어느 콘텐츠에서, 어떤 메뉴를, 왜 언급했는가?"**이기 때문입니다.
|
||||
|
||||
기존 맛집 서비스는 대체로 다수 이용자의 별점·후기, 예약 가능 여부, 지역 검색을 중심으로 설계돼 있습니다. 이 방식은 넓은 선택지를 빠르게 보여 주는 데 유용하지만, 영상을 보고 특정 사람의 선택을 기억한 사용자에게는 두 가지 공백이 남습니다. 첫째, 영상 속 식당의 이름·주소·메뉴가 콘텐츠 안에 흩어져 있어 나중에 다시 찾기 어렵습니다. 둘째, 평균 별점만으로는 왜 그 사람이 그 식당을 언급했는지, 내가 오늘 갈 이유가 있는지 판단하기 어렵습니다.
|
||||
|
||||
Tasteby의 차별점은 세 가지입니다.
|
||||
|
||||
첫째, **출처가 있는 발견**입니다. 식당을 보여 줄 때 원본 콘텐츠와 메뉴·언급 맥락을 함께 연결합니다. 사용자는 Tasteby의 요약만 믿을 필요 없이 원본으로 돌아가 확인할 수 있습니다. 추천인지 단순 언급인지, 협찬 또는 정정 정보가 확인되는 경우에는 이를 구분해 보이는 방향으로 신뢰를 설계합니다.
|
||||
|
||||
둘째, **분야별 큐레이터의 선택을 탐색 기준으로 사용**합니다. 사용자는 무작위 목록이 아니라 자신이 신뢰하는 미식 큐레이터, 먹고 싶은 메뉴, 갈 지역을 함께 놓고 후보를 좁힐 수 있습니다. 이는 "유명해서"가 아니라 특정 음식과 상황을 꾸준히 다뤄 온 사람의 관점을 발견의 출발점으로 삼는 방식입니다.
|
||||
|
||||
셋째, **개인의 맛 기억을 기본 비공개로 보존**합니다. 사용자는 방문 뒤 좋았던 이유와 다음에 갈 조건을 자기 메모로 남길 수 있습니다. 공개 리뷰를 많이 쓰게 하는 대신, 먼저 나를 위한 기록이 다음 선택에 다시 쓰이도록 하는 것이 목표입니다. 나중에 사용자가 원할 때만 일부 후보를 동행에게 공유할 수 있으며, 비공개 메모는 공유되지 않습니다.
|
||||
|
||||
이 구조는 국내에만 적용되는 것이 아닙니다. 현재도 한국 큐레이터가 다룬 일본·미국·싱가포르 등 해외 식당 60여 곳이 같은 방식으로 쌓이고 있습니다. 여행지에서 익명 리뷰를 처음부터 다시 읽는 대신, 이미 신뢰하는 사람의 선택을 그대로 꺼내 쓸 수 있다는 뜻입니다.
|
||||
|
||||
Tasteby가 해결하려는 문제는 정보 부족이 아니라 **신뢰할 만한 정보를 다시 쓸 수 없는 문제**입니다. 음식 콘텐츠를 보는 사람은 다음 식사를 더 쉽게 결정하고, 크리에이터는 자신의 콘텐츠가 일회성 조회를 넘어 정정 가능하고 탐색 가능한 아카이브로 이어질 수 있습니다. AI는 이 구조를 빠르게 만들지만, 경쟁력의 핵심은 AI 자체가 아니라 출처를 보존하고 개인의 선택으로 이어 주는 제품 경험입니다.
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
Tasteby의 수익 원칙은 분명합니다. **사용자의 비공개 찜과 메모를 판매하지 않고, 돈을 낸 식당이 자연 추천·큐레이터 출처·사용자 기록의 순서를 바꾸지 않게 한다**는 것입니다. 신뢰가 제품의 출발점이므로 단기 매출을 위해 이 원칙을 훼손하면 사업 자체가 약해집니다.
|
||||
|
||||
첫 번째 수익원은 공개 탐색 화면의 **명시형 문맥 광고와 프로모션**입니다. 예를 들어 사용자가 공개된 식당·메뉴·상황 페이지에서 정보를 찾을 때, 해당 맥락에 맞는 행사·신메뉴·예약 가능 정보 등을 `광고` 또는 `프로모션`으로 명확히 구분해 노출합니다. 광고주는 의사결정을 앞둔 공개 독자에게 도달할 기회를 구매하고, 사용자는 광고와 큐레이터의 자연 언급을 혼동하지 않습니다. 이 모델은 충분한 공개 탐색 세션과 신뢰 기준이 생긴 뒤 소규모로 검증합니다.
|
||||
|
||||
두 번째는 식당·브랜드의 **투명한 캠페인 상품**입니다. 신메뉴, 지역 행사, 예약 가능 정보처럼 사용자의 의사결정에 실질적으로 도움이 되는 정보를 공개 페이지의 별도 영역에서 제공합니다. 유료 여부는 표기하고, 광고비가 검색·추천·공개 리뷰의 순위를 바꾸지 않게 운영합니다. 따라서 판매 단위는 "상위 노출 보장"이 아니라, 표기된 캠페인의 도달과 행동 결과입니다.
|
||||
|
||||
세 번째는 사용자가 거래를 원할 때만 연결하는 **예약·주문 제휴 수수료**입니다. Tasteby가 사용자를 수수료가 높은 식당으로 유도하지 않고, 사용자가 이미 고른 식당에서 예약·주문을 원할 때만 제휴 경로를 제공합니다. 이 수익원은 사용자 행동과 파트너 연동이 검증된 뒤 도입합니다.
|
||||
|
||||
추가로, 크리에이터가 자신의 출처·정정·아카이브 관리를 원한다면 공식 큐레이터 페이지와 관리 도구를 유료 또는 수익 분배 방식으로 검토할 수 있습니다. 다만 기존 콘텐츠를 단순 재포장해 과금하지 않고, 크리에이터와 시청자의 재탐색 문제를 실제로 줄이는 경우에만 추진합니다.
|
||||
|
||||
초기 12개월의 목표는 매출을 과장하는 것이 아니라, 출처 기반 탐색 → 후보 저장 → 재열람이 반복되는 공개 의사결정 문맥을 검증하는 것입니다. 그 증거가 생긴 뒤 광고·프로모션·제휴를 순서대로 시험해 신뢰를 지키며 매출을 만든다는 계획입니다.
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 아이디어 단계에 머물지 않고, 큐레이터 출처·식당·메뉴 탐색, 지도 기반 발견, 회원·찜·공개 리뷰·비공개 메모를 갖춘 서비스를 직접 개발해 운영하고 있습니다. 2026년 9월 기준 등록 채널 6곳, 수집 영상 909편에서 추출해 좌표까지 연결한 식당 500곳을 확보했고, 그중에는 일본 28곳을 포함한 해외 식당 60여 곳이 이미 포함돼 있습니다. 저는 Spring Boot와 Next.js를 중심으로 백엔드·프론트엔드·데이터 파이프라인·배포 환경을 직접 설계하고 구현했습니다.
|
||||
|
||||
다음 단계의 사업화는 전국의 모든 맛집을 한꺼번에 늘리는 방식이 아닙니다. `큐레이터 1명 × 지역 1곳 × 메뉴 또는 식사 상황 1개`라는 작은 시장에서 출처 정확도와 실제 사용 행동을 먼저 증명하겠습니다.
|
||||
|
||||
**0~3개월에는 수량보다 신뢰도를 먼저 올리겠습니다.** 현재 LLM 검증을 거치지 않은 영상-식당 연결이 1,071건 남아 있습니다. 이를 정리해 출처와 메뉴 연결이 검증된 데이터만 노출하고, 오류 정정 경로와 `발견 → 원본 확인 → 후보 저장`의 행동 계측을 갖추겠습니다. 데이터는 채널을 10곳으로 늘려 식당 1,500곳 규모를 목표로 하되, 정확도 기준을 통과한 것만 셈에 넣겠습니다.
|
||||
|
||||
**4~6개월에는 첫 사용자 집단을 만들겠습니다.** 현재는 공개 회원 모집을 시작하지 않았고 제품과 데이터 품질을 먼저 확보하는 단계입니다. 따라서 이 구간의 핵심 과제는 방문자 수를 늘리는 것이 아니라, "영상 속 그 집을 오늘의 후보로"라는 문제를 이미 가진 사용자를 검색·커뮤니티·콘텐츠를 통해 정확한 출처 페이지로 데려와 탐색과 저장이 반복되는지 확인하는 것입니다. 동시에 큐레이터 또는 매니저에게 단순 홍보 요청이 아니라 오래된 콘텐츠의 출처 정리·정정·시청자 재탐색이라는 가치를 제안해 파트너십 3건을 협의하겠습니다.
|
||||
|
||||
**7~12개월에는 검증 결과를 확장하겠습니다.** 이미 확보한 일본 28곳은 한국 큐레이터가 현지에서 남긴 기록이므로, 새로운 데이터 수집 없이도 여행 사용 맥락을 검증할 출발점이 됩니다. 여기에 사용자가 찜한 후보를 동행과 함께 고르는 공유 기능을 더하겠습니다. 목표는 MAU 5만과 B2B 캠페인 20건이지만, 이 수치는 단순 방문자 수가 아니라 출처 확인·후보 저장·재열람·공유 수신자의 탐색으로 검증하겠습니다. 첫 매출은 자연 추천과 분리된 공개 문맥 광고 또는 투명한 캠페인 상품에서 만들 계획입니다.
|
||||
|
||||
사업화의 핵심 위험은 기술보다 신뢰입니다. 따라서 원본 링크를 보존하고, 협찬·정정 상태를 관리하며, 비공개 메모를 광고 타기팅에 쓰지 않겠습니다. 저는 "더 많은 식당"이 아니라 "다시 쓰이는 신뢰"를 증명하겠습니다.
|
||||
|
||||
> 제출 전 사실 확인: 위 실측치(채널 6·영상 909·식당 500·미검증 1,071·해외 60여)는 2026-09-15 기준이다. 제출일에 다시 조회해 갱신한다.
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
저는 Tasteby의 제품과 기술 구현은 직접 추진해 왔지만, 다음 단계에서 필요한 것은 개발 조언보다 **신뢰를 훼손하지 않는 시장 진입과 계약의 기준**입니다. 책임멘토에게 네 가지 도움을 받고 싶습니다.
|
||||
|
||||
첫째, 크리에이터 파트너십의 실무입니다. Tasteby는 타인의 콘텐츠를 대신 소비시키는 서비스가 아니라 원본으로 다시 연결하는 서비스여야 합니다. 큐레이터·매니저에게 어떤 가치 제안을 해야 하는지, 출처·초상·인용·협찬 표기를 어떤 계약과 운영 절차로 정리해야 하는지 조언을 받고 싶습니다.
|
||||
|
||||
둘째, 초기 B2B 상품의 검증입니다. 식당이나 브랜드가 돈을 낸다고 해서 자연 추천 순위가 바뀌면 Tasteby의 차별점은 사라집니다. 공개 탐색 문맥에서 사용자가 받아들일 수 있는 광고·프로모션의 형태, 가격 이전에 검증해야 할 성과 지표, 첫 고객을 찾는 영업 경로를 함께 설계하고 싶습니다.
|
||||
|
||||
셋째, 초기 사용자 획득 전략입니다. 검색·커뮤니티·콘텐츠 중 어떤 좁은 시장에서 출처 탐색과 후보 저장이 실제로 반복되는지, 작은 예산으로 무엇을 먼저 검증해야 하는지에 대한 피드백이 필요합니다. '바이럴'이나 조회 수가 아니라 재방문과 결정 행동으로 판단하는 방법을 배우고 싶습니다.
|
||||
|
||||
넷째, 해외 확장 우선순위입니다. 일본 여행 콘텐츠는 분명한 사용 사례이지만, 국내에서 어떤 데이터 품질과 파트너십 기준을 먼저 증명해야 하는지, 다국어·현지 정보·권리 이슈를 어떤 순서로 풀어야 하는지 검토받고 싶습니다.
|
||||
|
||||
멘토링을 통해 막연한 인맥 소개보다, 파트너십·수익·유통에서 반복 가능한 의사결정 기준을 얻고 싶습니다. 이를 바탕으로 1인 개발자가 만든 MVP를 신뢰할 수 있는 소비자 서비스와 지속 가능한 사업으로 확장하겠습니다.
|
||||
|
||||
## Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. (선택 / 유튜브 링크만)
|
||||
|
||||
**권장: 제출한다.** 75~90초 분량으로 아래 흐름을 사용한다.
|
||||
|
||||
1. 0~15초 — "그 영상의 그 식당, 어디였지?"라는 개인 경험과 재검색 장면
|
||||
2. 15~40초 — Tasteby에서 큐레이터·식당·메뉴·원본을 연결해 찾는 실제 화면
|
||||
3. 40~60초 — 찜과 비공개 메모, 동행과 후보를 고르는 공유 카드의 가치
|
||||
4. 60~80초 — AI는 정보를 구조화하고, Tasteby는 사람의 신뢰를 다시 쓰게 한다는 차별점
|
||||
5. 80~90초 — 12개월 검증 목표와 멘토링 요청
|
||||
|
||||
> 제출 전 입력: `[YouTube URL]`
|
||||
> 제작 원칙: Tasteby 자체 화면·직접 제작한 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원을 무단 삽입하지 않는다.
|
||||
|
||||
## Q6. 사업 분야를 선택해주세요. (필수 / 드롭다운)
|
||||
|
||||
**제출 전 실제 선택지 확인 후 선택한다.**
|
||||
|
||||
1순위는 `AI·데이터`다. Tasteby의 사용자 가치는 외식 발견이지만, 영상·글에서 식당 정보를 구조화하고 출처 기반으로 탐색하게 하는 핵심 실행 수단이 AI·데이터이기 때문이다. 해당 선택지가 없으면 2순위는 `플랫폼/O2O`, 그다음은 `푸드테크`다. 예약·배달 거래가 현재 핵심이 아니므로 관광·여행은 일본 베타 이후의 보조 분야로 둔다.
|
||||
|
||||
## Q7. 지원자의 현재 창업 여부를 알려주세요. (필수 / 택1)
|
||||
|
||||
**법적 사실 확인 전 선택하지 않는다.**
|
||||
|
||||
| 확인 결과 | 선택 |
|
||||
|---|---|
|
||||
| 본인 명의 사업자/법인의 창업일이 기준 기간에 없거나, 기창업자 요건에 해당하지 않음 | `예비창업자` |
|
||||
| 창업일이 2019-08-21~2026-08-20이고 Tasteby가 기존 사업과 다른 이종 창업 아이템임 | `기창업자` |
|
||||
|
||||
MVP를 개발하거나 도메인을 운영했다는 사실만으로 Q7을 판단하지 않는다. 사업자등록·법인 설립·공고의 세부 기준을 제출 전에 확인한다.
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
1차에서는 Tasteby를 "유튜브 맛집 영상에서 AI가 식당 정보를 자동으로 추출해 지도에 모아주는 서비스"로 설명했습니다. 타겟 규모와 기술 구성, 12개월 로드맵을 제시했지만 지원서를 다시 읽어 보니 네 가지가 비어 있었습니다. 제품을 정보 수집 기능으로만 설명했고, 수익 모델이 몇 줄의 나열에 그쳤으며, 목표 수치에 근거가 없었고, 멘토링 문항에는 멘토에게 받고 싶은 도움 대신 자금 사용 계획을 적었습니다.
|
||||
|
||||
**첫째, 제품의 정의를 바꿨습니다.** "AI가 맛집을 모아준다"에서 "신뢰하는 큐레이터의 출처로 발견하고, 내 비공개 기록으로 남겨 다음 식사에 다시 쓰고, 필요한 후보만 동행과 공유한다"는 사용 흐름으로 다시 썼습니다. 경쟁력은 수집 기술이 아니라 사용자가 신뢰를 다시 쓰게 만드는 구조에 있다고 판단했기 때문입니다.
|
||||
|
||||
**둘째, 수익 모델을 원칙과 순서로 정리했습니다.** 1차의 "유튜버 파트너십·식당 제휴·장기 데이터 사업" 나열 대신, 사용자의 비공개 기록을 판매하지 않고 광고비가 자연 추천 순위를 바꾸지 않는다는 원칙을 먼저 세웠습니다. 그 위에 공개 문맥 광고 → 투명한 캠페인 상품 → 사용자가 원할 때의 거래 제휴 순으로 검증 조건을 붙였습니다.
|
||||
|
||||
**셋째, 목표 수치를 실측에서 다시 세웠습니다.** 1차에 적은 "3개월 내 식당 5,000곳"은 현재 500곳 기준으로 10배여서 달성 가능한 계획이 아니었습니다. 2차에서는 채널 6곳·영상 909편·식당 500곳이라는 현재 값을 밝히고, 0~3개월의 과제를 수량 확대가 아니라 아직 검증되지 않은 영상-식당 연결 1,071건을 정리하는 일로 바꿨습니다. 공개 회원 모집을 아직 시작하지 않았다는 사실도 그대로 적었습니다.
|
||||
|
||||
**넷째, 멘토링 문항을 질문에 맞게 다시 썼습니다.** 자금 사용 계획 대신 크리에이터 계약 실무, B2B 상품 검증, 초기 사용자 획득, 해외 확장 우선순위 네 가지로 구체화했습니다.
|
||||
|
||||
1차가 "무엇을 만들 수 있는가"에 대한 답이었다면, 2차는 "누가 왜 다시 쓰고, 어떤 순서로 검증하며, 어떻게 사업이 되는가"에 대한 답입니다. 그사이 서비스도 멈춰 있지 않았습니다. 지역 표시 계층화, 언급이 적은 식당을 걸러내는 필터, 해외 식당의 국내 전용 예약 버튼 제거처럼 신뢰와 정확도에 관한 개선을 계속 반영해 왔습니다.
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. (선택 / 2,000자)
|
||||
|
||||
Tasteby의 가장 큰 강점 중 하나는 아이디어를 설명하는 데서 멈추지 않고, 제품으로 만들고 운영 가능한 형태로 옮겨 왔다는 점입니다. 저는 1인 풀스택 개발자로서 문제 정의부터 데이터 구조, 백엔드·프론트엔드 구현, AI 처리 파이프라인, 배포 환경까지 직접 설계하고 연결해 왔습니다.
|
||||
|
||||
Tasteby에서는 Spring Boot와 Java 기반의 서비스 로직, Next.js 기반의 사용자 화면, Oracle 23ai 벡터 데이터베이스와 Redis를 활용한 데이터 처리 구조를 구성했습니다. 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩·지도·검색으로 사용자가 다시 찾을 수 있게 만드는 파이프라인도 직접 만들었습니다. 기술을 개별 기능으로 쌓기보다, "출처를 찾는다 → 후보를 저장한다 → 방문 뒤 기억한다 → 다음 선택에 다시 쓴다"는 한 사용 흐름이 완성되도록 설계한 경험이 있습니다.
|
||||
|
||||
저의 실행 방식은 작은 가설을 빠르게 제품으로 옮기고, 실제 사용 행동으로 다음 우선순위를 정하는 것입니다. 예를 들어 Tasteby의 비공개 메모는 리뷰를 많이 받기 위한 기능이 아니라, 사용자가 좋았던 경험을 다음 외식에 다시 쓰게 하기 위한 기능입니다. 찜 공유 역시 전체 취향을 공개하는 기능이 아니라, 사용자가 고른 후보만 동행과 함께 결정하게 하는 기능으로 분리했습니다. 이처럼 기술의 가능성보다 사용자의 신뢰와 권한을 먼저 설계하는 것이 저의 제품 역량입니다.
|
||||
|
||||
또한 혼자서도 기획·개발·운영을 연결할 수 있지만, 모든 것을 혼자 해결하려 하지 않습니다. 크리에이터 계약, 저작권·표기, 초기 B2B 영업, 해외 확장은 멘토와 파트너의 전문성이 필요한 영역으로 분명히 인식하고 있습니다. 저는 빠르게 만들 수 있는 실행력과, 모르는 영역을 검증 가능한 질문으로 바꾸는 운영 방식을 바탕으로 Tasteby를 사업으로 성장시키겠습니다.
|
||||
|
||||
> 제출 전 보강 후보: 공개 가능한 직장 경력, 이전 프로젝트, 수상·자격, 서비스 운영 수치가 있으면 사실 확인 뒤 한 단락만 추가한다.
|
||||
|
||||
## Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. (선택 / 드롭다운)
|
||||
|
||||
`팀원 없음`
|
||||
|
||||
현재는 1인 창업자로 제품을 직접 개발·운영한다. 다만 법무·크리에이터 파트너십·B2B 영업은 외부 전문가 및 멘토와 보완할 계획이다.
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개 + 좋아요)
|
||||
|
||||
> **맛집 영상을 보다가 "그 집 어디였지?"를 되묻는 사람을 위해 만들었습니다.**
|
||||
> Tasteby는 신뢰하는 미식 큐레이터가 언급한 식당과 메뉴를 원본 출처와 함께 찾고, 마음에 드는 곳은 내 찜에 남겨 다음 식사에 다시 쓰게 합니다.
|
||||
> 좋은 한 끼를 발견하는 순간과, 좋았던 한 끼를 기억하는 순간을 연결합니다.
|
||||
> `www.tasteby.net`
|
||||
|
||||
> 게시 전: 실제 접속 URL과 대표 스크린샷을 확인한다.
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
제출 직전에 아래를 각각 읽고 동의한다.
|
||||
|
||||
- 참여 서약서
|
||||
- 본인 아이디어 확인 서약서
|
||||
- 비밀유지 서약서
|
||||
|
||||
## 사진 배분 계획 (전체 10장 제한)
|
||||
|
||||
| 문항 | 장수 | 권장 이미지 | 심사에서 보여 줄 사실 |
|
||||
|------|---:|---|---|
|
||||
| Q2 | 1 | 직접 만든 `영상 속 정보 → Tasteby 출처·지도 → 다음 식사` 흐름 도식 | 왜 이 서비스가 필요한가 |
|
||||
| Q3-1 | 3 | 지도 탐색, 식당 상세의 원본/메뉴 근거, 찜·비공개 메모 화면 | 출처·개인 기록의 차별점 |
|
||||
| Q4-1 | 2 | 데이터 처리·정정 흐름 도식, 12개월 로드맵 | 이미 만든 것과 다음 검증 순서 |
|
||||
| Q9 | 1 | 실제 서비스 아키텍처 또는 개발·배포 흐름 | 1인 실행 역량 |
|
||||
| Q11 | 1 | 모바일 또는 데스크톱 대표 화면 한 장 | 공개 소개의 첫 인상 |
|
||||
| 예비 | 2 | 수신자 공유 카드, 모바일 탐색 화면 | 심사 코멘트 대응 또는 품질이 높은 화면 교체 |
|
||||
|
||||
총 8장을 기본으로 사용하고 2장은 예비로 남긴다. 모든 화면은 제출일 기준 실제 동작·표현과 일치해야 하며, 원본 영상 캡처·타인 음식 사진은 사용권을 확인하지 못하면 사용하지 않는다.
|
||||
195
docs/ir/modu-startup-2026-09/v5.md
Normal file
195
docs/ir/modu-startup-2026-09/v5.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 모두의 창업 2차 지원서 — v5
|
||||
|
||||
> 작성일: 2026-09-15
|
||||
> 상태: **심사 기준에 맞춰 재정렬한 판.** `제출 전 확정` 표기 항목만 사실 확인 뒤 확정한다.
|
||||
|
||||
## v4 → v5 변경 요약
|
||||
- **Q4-1 재구성**: 심사 공통 항목이 "창업활동자금과 AI 솔루션을 활용해 **2개월 내 MVP 제작이 가능한 수준인가**"임을 확인 → 0~3/4~6/7~12개월 구조를 **"이미 운영 중 + 2개월 안에 하는 일"** 중심으로 재편. Tasteby는 이 항목에서 "만들 수 있다"가 아니라 "이미 만들어 운영 중"으로 답할 수 있는 드문 경우
|
||||
- **Q3-2 축소**: 광고·캠페인 상품 수익원 **삭제**. 유명 큐레이터의 추천이 강점인 서비스에 노출 판매를 붙이면 Q3-1에서 비판한 기존 서비스와 같아지고 차별성이 무너짐 → "지금은 매출이 아니라 사용을 검증하는 단계"로 줄이고, 수익화 축은 크리에이터 파트너십으로 단일화
|
||||
- **Q4-2·Q8도 동반 수정**: 광고 상품 검증을 전제한 서술을 걷어내고 크리에이터 수익 배분 설계로 교체 (문서 전체에서 "노출을 팔지 않는다"가 일관되게 읽히도록)
|
||||
- 예약·주문 제휴는 **조건부**로만 남김 (테이블링·캐치테이블의 외부 제휴 프로그램 존재가 확인되지 않음 — 확인 전에는 수익원으로 단정하지 않는다)
|
||||
|
||||
### 심사 기준 (확인 결과, 2026-09-15)
|
||||
- 주최: 중소벤처기업부 대국민 창업 오디션. 일반/기술트랙 4,000명 + 로컬트랙 1,000명 선발, 진출 시 창업활동자금 200만 원 + 책임멘토링 + AI 바우처
|
||||
- 심사 3축: **도전의 진정성 / 사회적 가치(독창성·차별성) / 아이디어 구체성(BM 현실성·단계별 로드맵)**
|
||||
- 공통 항목: **2개월 내 MVP 제작 가능 수준인가**
|
||||
- 출처: modoo.or.kr, 멘토기관 80여 곳 평가지표 정리 자료
|
||||
|
||||
## v3 → v4 변경 요약
|
||||
- **Q8 완성**: 1차 지원서 원문이 `v1.md`(사용자 제공 원고)임을 확인 → 대괄호를 실제 1차 내용으로 채움. 1차의 실제 약점 4가지(제품 정의·수익모델 나열·근거 없는 수치·멘토 문항 오답)와 2차의 수정을 1:1로 대응시킴
|
||||
|
||||
## v2 → v3 변경 요약
|
||||
- **Q4-1 전면 수정**: "3개월에 식당 5,000곳"(현재의 10배, 달성 불가) → 현재 실측치(채널 6·영상 909·식당 500)에서 출발하는 배수 목표로 교체. 0~3개월 과제를 수량이 아니라 **LLM 미검증 1,071건 정리**로 재정의
|
||||
- **Q4-1에 사용자 현황 명시**: 공개 회원 모집을 아직 시작하지 않은 단계임을 밝히고, 4~6개월의 핵심 과제를 첫 사용자 집단 확보로 지정
|
||||
- **Q3-1·Q4-1에 해외 데이터 반영**: 일본 28곳 포함 해외 60여 곳이 이미 축적됨 → 일본 확장이 "구상"이 아니라 "이미 시작된 축적"임을 근거로 제시
|
||||
- **깨진 참조 링크 3개 제거** (`docs/design/705-…`, `docs/strategy/…`, `docs/design/711-…` — 리포에 존재하지 않음)
|
||||
|
||||
> 실측 출처: 2026-09-15 Admin 화면 및 `GET /api/restaurants?limit=100000` 조회. 상세는 `README.md` 실측 지표 표.
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 10~100자)
|
||||
|
||||
> 신뢰하는 미식 큐레이터의 영상 속 맛집을 찾아, 나의 다음 식사와 기록으로 연결하는 Tasteby
|
||||
|
||||
- v2 검증: 54자. 제출 화면의 실제 글자 수를 최종 확인한다.
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
저는 맛집 영상을 보는 것을 좋아하지만, 막상 식사 약속이 잡히면 같은 문제를 반복해서 겪었습니다. "성시경 영상에서 본 그 국밥집이 어디였지?" 기억나는 것은 사람과 메뉴의 인상뿐이었습니다. 다시 영상을 찾아 자막을 넘기고, 식당 이름을 받아 적어 지도에 옮겨야 했습니다. 좋아하는 채널이 늘수록 저장한 정보도 늘었지만, 정작 필요한 순간에는 더 찾기 어려워졌습니다.
|
||||
|
||||
이 불편은 일본 여행에서 더 선명해졌습니다. 여행 전에 한국 미식 유튜버의 일본 맛집 영상을 여러 편 봤지만, 현지에서는 어느 영상의 어느 장면에 나온 식당인지 다시 찾는 데 시간이 들었습니다. 별점과 후기 수가 많은 식당은 쉽게 찾을 수 있었지만, 제가 실제로 궁금했던 것은 "내가 신뢰하는 이 사람이 왜 이곳을 골랐는가"였습니다. 영상, 지도, 메모앱이 각각 답의 일부만 갖고 있었습니다.
|
||||
|
||||
그래서 출발한 질문은 "맛집을 더 많이 모으려면 어떻게 해야 할까?"가 아니었습니다. **신뢰하는 사람의 선택을, 다음 식사를 고를 때 다시 쓸 수 있게 하려면 어떻게 해야 할까?**였습니다.
|
||||
|
||||
Tasteby는 미식 큐레이터의 영상·글 속 식당, 메뉴, 언급 맥락을 구조화해 지도와 탐색 화면에서 찾게 하는 서비스입니다. 사용자는 원본 콘텐츠로 다시 돌아가 맥락을 확인할 수 있고, 마음에 드는 곳은 자신의 찜과 비공개 메모에 남길 수 있습니다. 즉, Tasteby는 원본 영상을 대체하거나 익명 다수의 평가를 더 크게 만드는 서비스가 아니라, 흩어진 신뢰의 단서를 실제 외식 결정에 쓸 수 있게 연결하는 도구입니다.
|
||||
|
||||
AI는 이 일을 가능하게 하는 수단입니다. 영상 자막과 공개 정보를 바탕으로 식당 후보를 구조화하되, 원본 출처를 남기고 오류는 정정할 수 있게 설계합니다. 저는 "AI가 맛집을 대신 추천한다"보다 "사람이 쌓아 온 신뢰를 사용자가 다시 쓸 수 있게 한다"는 방향이 더 오래 갈 수 있다고 믿습니다. Tasteby는 좋은 한 끼를 찾는 순간과, 좋았던 한 끼를 다시 기억하는 순간을 하나의 경험으로 만들고자 합니다.
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 또 하나의 맛집 순위 서비스가 아닙니다. 출발점이 "평점이 높은 곳은 어디인가?"가 아니라 **"내가 신뢰하는 사람이 어느 콘텐츠에서, 어떤 메뉴를, 왜 언급했는가?"**이기 때문입니다.
|
||||
|
||||
기존 맛집 서비스는 대체로 다수 이용자의 별점·후기, 예약 가능 여부, 지역 검색을 중심으로 설계돼 있습니다. 이 방식은 넓은 선택지를 빠르게 보여 주는 데 유용하지만, 영상을 보고 특정 사람의 선택을 기억한 사용자에게는 두 가지 공백이 남습니다. 첫째, 영상 속 식당의 이름·주소·메뉴가 콘텐츠 안에 흩어져 있어 나중에 다시 찾기 어렵습니다. 둘째, 평균 별점만으로는 왜 그 사람이 그 식당을 언급했는지, 내가 오늘 갈 이유가 있는지 판단하기 어렵습니다.
|
||||
|
||||
Tasteby의 차별점은 세 가지입니다.
|
||||
|
||||
첫째, **출처가 있는 발견**입니다. 식당을 보여 줄 때 원본 콘텐츠와 메뉴·언급 맥락을 함께 연결합니다. 사용자는 Tasteby의 요약만 믿을 필요 없이 원본으로 돌아가 확인할 수 있습니다. 추천인지 단순 언급인지, 협찬 또는 정정 정보가 확인되는 경우에는 이를 구분해 보이는 방향으로 신뢰를 설계합니다.
|
||||
|
||||
둘째, **분야별 큐레이터의 선택을 탐색 기준으로 사용**합니다. 사용자는 무작위 목록이 아니라 자신이 신뢰하는 미식 큐레이터, 먹고 싶은 메뉴, 갈 지역을 함께 놓고 후보를 좁힐 수 있습니다. 이는 "유명해서"가 아니라 특정 음식과 상황을 꾸준히 다뤄 온 사람의 관점을 발견의 출발점으로 삼는 방식입니다.
|
||||
|
||||
셋째, **개인의 맛 기억을 기본 비공개로 보존**합니다. 사용자는 방문 뒤 좋았던 이유와 다음에 갈 조건을 자기 메모로 남길 수 있습니다. 공개 리뷰를 많이 쓰게 하는 대신, 먼저 나를 위한 기록이 다음 선택에 다시 쓰이도록 하는 것이 목표입니다. 나중에 사용자가 원할 때만 일부 후보를 동행에게 공유할 수 있으며, 비공개 메모는 공유되지 않습니다.
|
||||
|
||||
이 구조는 국내에만 적용되는 것이 아닙니다. 현재도 한국 큐레이터가 다룬 일본·미국·싱가포르 등 해외 식당 60여 곳이 같은 방식으로 쌓이고 있습니다. 여행지에서 익명 리뷰를 처음부터 다시 읽는 대신, 이미 신뢰하는 사람의 선택을 그대로 꺼내 쓸 수 있다는 뜻입니다.
|
||||
|
||||
Tasteby가 해결하려는 문제는 정보 부족이 아니라 **신뢰할 만한 정보를 다시 쓸 수 없는 문제**입니다. 음식 콘텐츠를 보는 사람은 다음 식사를 더 쉽게 결정하고, 크리에이터는 자신의 콘텐츠가 일회성 조회를 넘어 정정 가능하고 탐색 가능한 아카이브로 이어질 수 있습니다. AI는 이 구조를 빠르게 만들지만, 경쟁력의 핵심은 AI 자체가 아니라 출처를 보존하고 개인의 선택으로 이어 주는 제품 경험입니다.
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
Tasteby는 지금 매출을 만드는 단계가 아니라, 사람들이 실제로 다시 쓰는지 검증하는 단계입니다. 그래서 수익 모델도 크게 벌이기보다 **서비스의 강점을 훼손하지 않는 방식**을 먼저 정해 두었습니다.
|
||||
|
||||
먼저 하지 않기로 한 것이 있습니다. **검색 결과나 추천 순위를 판매하지 않습니다.** Tasteby를 찾는 이유는 신뢰하는 사람이 고른 집을 보기 위해서입니다. 그 화면에 돈을 낸 식당이 섞이는 순간, 옆에 있는 진짜 추천까지 의심받습니다. 기존 맛집 서비스가 잃은 것이 정확히 그 신뢰이므로, 노출을 파는 방식은 처음부터 배제합니다.
|
||||
|
||||
수익의 축은 **크리에이터 파트너십**입니다. 미식 크리에이터에게 채널 공식 페이지를 제공해 영상 속 식당이 검색 가능한 아카이브로 남게 하고, 그 페이지에서 발생한 성과를 크리에이터와 나눕니다. 크리에이터가 이미 영상에서 추천한 가게를 다루는 구조이므로 추천의 순수성이 유지되고, 크리에이터가 수익을 얻으면 Tasteby를 알릴 이유도 함께 생깁니다. 광고와는 방향이 반대입니다.
|
||||
|
||||
사용자가 스스로 예약이나 주문을 원할 때 연결하는 제휴 수수료는 다음 단계의 선택지로 둡니다. 현재 서비스에는 예약 링크가 연결된 식당이 이미 300곳 이상 있지만, 예약 플랫폼의 제휴 조건을 확인하기 전까지는 수익원으로 단정하지 않겠습니다.
|
||||
|
||||
12개월 안에 큰 매출을 약속드리지는 않겠습니다. 이 기간의 목표는 크리에이터 3팀과 실제 파트너십을 맺어 수익 배분 구조를 한 번 돌려 보는 것이고, 본격적인 수익화는 사용자가 반복해서 돌아온다는 증거가 쌓인 뒤의 일입니다.
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
**Tasteby는 기획안이 아니라 이미 동작하는 서비스입니다.** www.tasteby.net 에서 운영 중이며, 2026년 9월 기준 등록 채널 6곳, 수집 영상 909편에서 추출해 좌표까지 연결한 식당 500곳이 들어 있습니다. 그중 일본 28곳을 비롯한 해외 식당이 60여 곳이고, 예약 링크가 연결된 식당도 300곳이 넘습니다. 큐레이터·지역·메뉴로 좁혀 찾는 탐색, 지도 기반 발견, 회원·찜·공개 리뷰·비공개 메모까지 사용자가 한 바퀴 도는 흐름이 모두 구현돼 있습니다. 저는 이 전부를 Spring Boot와 Next.js로 직접 설계하고 구현해 클라우드에 배포했습니다.
|
||||
|
||||
그래서 저에게 2개월은 무언가를 처음 만드는 기간이 아니라, **이미 만든 것을 사람들 앞에 내놓는 기간**입니다.
|
||||
|
||||
**2개월 안에 하는 일은 세 가지입니다.** 첫째, 데이터의 정확도를 끝까지 올리겠습니다. 현재 LLM 검증을 거치지 않은 영상-식당 연결이 1,071건 남아 있습니다. AI 솔루션을 활용해 이를 모두 검증하고, 잘못 연결된 항목을 정리해 출처가 확인된 식당만 노출하겠습니다. 둘째, 채널을 10곳으로 늘려 식당 1,500곳 규모를 만들되 정확도 기준을 통과한 것만 셈에 넣겠습니다. 셋째, 아직 시작하지 않은 공개 사용자 모집을 열고, `발견 → 원본 확인 → 후보 저장 → 재방문`이 실제로 이어지는지 계측하겠습니다. 2개월 뒤에 제가 보여드릴 것은 기능 시연이 아니라, **검증된 데이터 위에서 사람들이 실제로 어떻게 움직였는가** 입니다.
|
||||
|
||||
**그 다음은 신뢰를 파트너십으로 넓히는 단계입니다.** 미식 크리에이터에게 오래된 영상이 검색 가능한 아카이브로 남는다는 가치를 제안해 6개월 안에 3팀과 협력하겠습니다. 이때 필요한 계약·저작권·표기 기준은 책임멘토의 도움을 받고자 합니다. 12개월 시점에는 이미 쌓여 있는 일본 데이터를 바탕으로 여행 사용 맥락을 검증하고, 찜한 후보를 동행과 함께 고르는 공유 기능을 더하겠습니다.
|
||||
|
||||
가장 큰 위험은 기술이 아니라 신뢰입니다. 원본 링크를 반드시 보존하고, 협찬과 정정 상태를 관리하며, 사용자의 비공개 메모는 어떤 경우에도 광고나 외부 판매에 쓰지 않겠습니다. "더 많은 식당"이 아니라 "다시 쓰이는 신뢰"를 증명하는 것이 Tasteby의 사업화입니다.
|
||||
|
||||
> 제출 전 사실 확인: 실측치(채널 6·영상 909·식당 500·미검증 1,071·해외 60여·예약링크 300여)는 2026-09-15 기준. 제출일에 재조회해 갱신한다.
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
저는 Tasteby의 제품과 기술 구현은 직접 추진해 왔지만, 다음 단계에서 필요한 것은 개발 조언보다 **신뢰를 훼손하지 않는 시장 진입과 계약의 기준**입니다. 책임멘토에게 네 가지 도움을 받고 싶습니다.
|
||||
|
||||
첫째, 크리에이터 파트너십의 실무입니다. Tasteby는 타인의 콘텐츠를 대신 소비시키는 서비스가 아니라 원본으로 다시 연결하는 서비스여야 합니다. 큐레이터·매니저에게 어떤 가치 제안을 해야 하는지, 출처·초상·인용·협찬 표기를 어떤 계약과 운영 절차로 정리해야 하는지 조언을 받고 싶습니다.
|
||||
|
||||
둘째, 신뢰를 해치지 않는 수익 구조의 설계입니다. Tasteby는 검색 결과나 추천 순위를 판매하지 않기로 했기 때문에, 남는 길은 크리에이터와 함께 버는 구조입니다. 채널 공식 페이지의 성과를 어떤 기준으로 나눠야 크리에이터와 서비스 모두에게 지속 가능한지, 예약·주문 연결처럼 사용자가 먼저 원할 때만 작동하는 수익원은 어떤 조건에서 성립하는지 조언을 받고 싶습니다.
|
||||
|
||||
셋째, 초기 사용자 획득 전략입니다. 검색·커뮤니티·콘텐츠 중 어떤 좁은 시장에서 출처 탐색과 후보 저장이 실제로 반복되는지, 작은 예산으로 무엇을 먼저 검증해야 하는지에 대한 피드백이 필요합니다. '바이럴'이나 조회 수가 아니라 재방문과 결정 행동으로 판단하는 방법을 배우고 싶습니다.
|
||||
|
||||
넷째, 해외 확장 우선순위입니다. 일본 여행 콘텐츠는 분명한 사용 사례이지만, 국내에서 어떤 데이터 품질과 파트너십 기준을 먼저 증명해야 하는지, 다국어·현지 정보·권리 이슈를 어떤 순서로 풀어야 하는지 검토받고 싶습니다.
|
||||
|
||||
멘토링을 통해 막연한 인맥 소개보다, 파트너십·수익·유통에서 반복 가능한 의사결정 기준을 얻고 싶습니다. 이를 바탕으로 1인 개발자가 만든 MVP를 신뢰할 수 있는 소비자 서비스와 지속 가능한 사업으로 확장하겠습니다.
|
||||
|
||||
## Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. (선택 / 유튜브 링크만)
|
||||
|
||||
**권장: 제출한다.** 75~90초 분량으로 아래 흐름을 사용한다.
|
||||
|
||||
1. 0~15초 — "그 영상의 그 식당, 어디였지?"라는 개인 경험과 재검색 장면
|
||||
2. 15~40초 — Tasteby에서 큐레이터·식당·메뉴·원본을 연결해 찾는 실제 화면
|
||||
3. 40~60초 — 찜과 비공개 메모, 동행과 후보를 고르는 공유 카드의 가치
|
||||
4. 60~80초 — AI는 정보를 구조화하고, Tasteby는 사람의 신뢰를 다시 쓰게 한다는 차별점
|
||||
5. 80~90초 — 12개월 검증 목표와 멘토링 요청
|
||||
|
||||
> 제출 전 입력: `[YouTube URL]`
|
||||
> 제작 원칙: Tasteby 자체 화면·직접 제작한 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원을 무단 삽입하지 않는다.
|
||||
|
||||
## Q6. 사업 분야를 선택해주세요. (필수 / 드롭다운)
|
||||
|
||||
**제출 전 실제 선택지 확인 후 선택한다.**
|
||||
|
||||
1순위는 `AI·데이터`다. Tasteby의 사용자 가치는 외식 발견이지만, 영상·글에서 식당 정보를 구조화하고 출처 기반으로 탐색하게 하는 핵심 실행 수단이 AI·데이터이기 때문이다. 해당 선택지가 없으면 2순위는 `플랫폼/O2O`, 그다음은 `푸드테크`다. 예약·배달 거래가 현재 핵심이 아니므로 관광·여행은 일본 베타 이후의 보조 분야로 둔다.
|
||||
|
||||
## Q7. 지원자의 현재 창업 여부를 알려주세요. (필수 / 택1)
|
||||
|
||||
**법적 사실 확인 전 선택하지 않는다.**
|
||||
|
||||
| 확인 결과 | 선택 |
|
||||
|---|---|
|
||||
| 본인 명의 사업자/법인의 창업일이 기준 기간에 없거나, 기창업자 요건에 해당하지 않음 | `예비창업자` |
|
||||
| 창업일이 2019-08-21~2026-08-20이고 Tasteby가 기존 사업과 다른 이종 창업 아이템임 | `기창업자` |
|
||||
|
||||
MVP를 개발하거나 도메인을 운영했다는 사실만으로 Q7을 판단하지 않는다. 사업자등록·법인 설립·공고의 세부 기준을 제출 전에 확인한다.
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
1차에서는 Tasteby를 "유튜브 맛집 영상에서 AI가 식당 정보를 자동으로 추출해 지도에 모아주는 서비스"로 설명했습니다. 타겟 규모와 기술 구성, 12개월 로드맵을 제시했지만 지원서를 다시 읽어 보니 네 가지가 비어 있었습니다. 제품을 정보 수집 기능으로만 설명했고, 수익 모델이 몇 줄의 나열에 그쳤으며, 목표 수치에 근거가 없었고, 멘토링 문항에는 멘토에게 받고 싶은 도움 대신 자금 사용 계획을 적었습니다.
|
||||
|
||||
**첫째, 제품의 정의를 바꿨습니다.** "AI가 맛집을 모아준다"에서 "신뢰하는 큐레이터의 출처로 발견하고, 내 비공개 기록으로 남겨 다음 식사에 다시 쓰고, 필요한 후보만 동행과 공유한다"는 사용 흐름으로 다시 썼습니다. 경쟁력은 수집 기술이 아니라 사용자가 신뢰를 다시 쓰게 만드는 구조에 있다고 판단했기 때문입니다.
|
||||
|
||||
**둘째, 수익 모델에서 하지 않을 것을 먼저 정했습니다.** 1차의 "유튜버 파트너십·식당 제휴·장기 데이터 사업" 나열 대신, 검색 결과와 추천 순위는 판매하지 않는다는 원칙을 세웠습니다. 신뢰하는 사람이 고른 집을 보러 온 화면에 돈을 낸 가게가 섞이면 진짜 추천까지 의심받고, 그것이 기존 맛집 서비스가 신뢰를 잃은 이유이기 때문입니다. 대신 이미 영상에서 추천된 가게를 다루는 크리에이터 파트너십을 수익의 축으로 단일화했습니다.
|
||||
|
||||
**셋째, 목표 수치를 실측에서 다시 세웠습니다.** 1차에 적은 "3개월 내 식당 5,000곳"은 현재 500곳 기준으로 10배여서 달성 가능한 계획이 아니었습니다. 2차에서는 채널 6곳·영상 909편·식당 500곳이라는 현재 값을 밝히고, 0~3개월의 과제를 수량 확대가 아니라 아직 검증되지 않은 영상-식당 연결 1,071건을 정리하는 일로 바꿨습니다. 공개 회원 모집을 아직 시작하지 않았다는 사실도 그대로 적었습니다.
|
||||
|
||||
**넷째, 멘토링 문항을 질문에 맞게 다시 썼습니다.** 자금 사용 계획 대신 크리에이터 계약 실무, B2B 상품 검증, 초기 사용자 획득, 해외 확장 우선순위 네 가지로 구체화했습니다.
|
||||
|
||||
1차가 "무엇을 만들 수 있는가"에 대한 답이었다면, 2차는 "누가 왜 다시 쓰고, 어떤 순서로 검증하며, 어떻게 사업이 되는가"에 대한 답입니다. 그사이 서비스도 멈춰 있지 않았습니다. 지역 표시 계층화, 언급이 적은 식당을 걸러내는 필터, 해외 식당의 국내 전용 예약 버튼 제거처럼 신뢰와 정확도에 관한 개선을 계속 반영해 왔습니다.
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. (선택 / 2,000자)
|
||||
|
||||
Tasteby의 가장 큰 강점 중 하나는 아이디어를 설명하는 데서 멈추지 않고, 제품으로 만들고 운영 가능한 형태로 옮겨 왔다는 점입니다. 저는 1인 풀스택 개발자로서 문제 정의부터 데이터 구조, 백엔드·프론트엔드 구현, AI 처리 파이프라인, 배포 환경까지 직접 설계하고 연결해 왔습니다.
|
||||
|
||||
Tasteby에서는 Spring Boot와 Java 기반의 서비스 로직, Next.js 기반의 사용자 화면, Oracle 23ai 벡터 데이터베이스와 Redis를 활용한 데이터 처리 구조를 구성했습니다. 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩·지도·검색으로 사용자가 다시 찾을 수 있게 만드는 파이프라인도 직접 만들었습니다. 기술을 개별 기능으로 쌓기보다, "출처를 찾는다 → 후보를 저장한다 → 방문 뒤 기억한다 → 다음 선택에 다시 쓴다"는 한 사용 흐름이 완성되도록 설계한 경험이 있습니다.
|
||||
|
||||
저의 실행 방식은 작은 가설을 빠르게 제품으로 옮기고, 실제 사용 행동으로 다음 우선순위를 정하는 것입니다. 예를 들어 Tasteby의 비공개 메모는 리뷰를 많이 받기 위한 기능이 아니라, 사용자가 좋았던 경험을 다음 외식에 다시 쓰게 하기 위한 기능입니다. 찜 공유 역시 전체 취향을 공개하는 기능이 아니라, 사용자가 고른 후보만 동행과 함께 결정하게 하는 기능으로 분리했습니다. 이처럼 기술의 가능성보다 사용자의 신뢰와 권한을 먼저 설계하는 것이 저의 제품 역량입니다.
|
||||
|
||||
또한 혼자서도 기획·개발·운영을 연결할 수 있지만, 모든 것을 혼자 해결하려 하지 않습니다. 크리에이터 계약, 저작권·표기, 초기 B2B 영업, 해외 확장은 멘토와 파트너의 전문성이 필요한 영역으로 분명히 인식하고 있습니다. 저는 빠르게 만들 수 있는 실행력과, 모르는 영역을 검증 가능한 질문으로 바꾸는 운영 방식을 바탕으로 Tasteby를 사업으로 성장시키겠습니다.
|
||||
|
||||
> 제출 전 보강 후보: 공개 가능한 직장 경력, 이전 프로젝트, 수상·자격, 서비스 운영 수치가 있으면 사실 확인 뒤 한 단락만 추가한다.
|
||||
|
||||
## Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. (선택 / 드롭다운)
|
||||
|
||||
`팀원 없음`
|
||||
|
||||
현재는 1인 창업자로 제품을 직접 개발·운영한다. 다만 법무·크리에이터 파트너십·B2B 영업은 외부 전문가 및 멘토와 보완할 계획이다.
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개 + 좋아요)
|
||||
|
||||
> **맛집 영상을 보다가 "그 집 어디였지?"를 되묻는 사람을 위해 만들었습니다.**
|
||||
> Tasteby는 신뢰하는 미식 큐레이터가 언급한 식당과 메뉴를 원본 출처와 함께 찾고, 마음에 드는 곳은 내 찜에 남겨 다음 식사에 다시 쓰게 합니다.
|
||||
> 좋은 한 끼를 발견하는 순간과, 좋았던 한 끼를 기억하는 순간을 연결합니다.
|
||||
> `www.tasteby.net`
|
||||
|
||||
> 게시 전: 실제 접속 URL과 대표 스크린샷을 확인한다.
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
제출 직전에 아래를 각각 읽고 동의한다.
|
||||
|
||||
- 참여 서약서
|
||||
- 본인 아이디어 확인 서약서
|
||||
- 비밀유지 서약서
|
||||
|
||||
## 사진 배분 계획 (전체 10장 제한)
|
||||
|
||||
| 문항 | 장수 | 권장 이미지 | 심사에서 보여 줄 사실 |
|
||||
|------|---:|---|---|
|
||||
| Q2 | 1 | 직접 만든 `영상 속 정보 → Tasteby 출처·지도 → 다음 식사` 흐름 도식 | 왜 이 서비스가 필요한가 |
|
||||
| Q3-1 | 3 | 지도 탐색, 식당 상세의 원본/메뉴 근거, 찜·비공개 메모 화면 | 출처·개인 기록의 차별점 |
|
||||
| Q4-1 | 2 | 데이터 처리·정정 흐름 도식, 12개월 로드맵 | 이미 만든 것과 다음 검증 순서 |
|
||||
| Q9 | 1 | 실제 서비스 아키텍처 또는 개발·배포 흐름 | 1인 실행 역량 |
|
||||
| Q11 | 1 | 모바일 또는 데스크톱 대표 화면 한 장 | 공개 소개의 첫 인상 |
|
||||
| 예비 | 2 | 수신자 공유 카드, 모바일 탐색 화면 | 심사 코멘트 대응 또는 품질이 높은 화면 교체 |
|
||||
|
||||
총 8장을 기본으로 사용하고 2장은 예비로 남긴다. 모든 화면은 제출일 기준 실제 동작·표현과 일치해야 하며, 원본 영상 캡처·타인 음식 사진은 사용권을 확인하지 못하면 사용하지 않는다.
|
||||
207
docs/ir/modu-startup-2026-09/v6.md
Normal file
207
docs/ir/modu-startup-2026-09/v6.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# 모두의 창업 2차 지원서 — v6
|
||||
|
||||
> 작성일: 2026-09-15
|
||||
> 상태: **Q5·Q11까지 채운 판.** 남은 것은 Q6(드롭다운 실물)·Q7(사업자 상태)·사진 8장뿐이다.
|
||||
|
||||
## v5 → v6 변경 요약
|
||||
- **Q11 완성**: 홈페이지 공개용 소개문 작성. 심사 문서 톤이 아니라 일반 독자가 읽고 좋아요를 누를 톤으로 — 문제 공감 → 서비스 설명 → 사람이 기준이라는 차별점 → 현재 규모 → 링크
|
||||
- **Q5 대본 작성**: `q5-video-script.md`에 85초 컷 구성(9컷). 화면·자막·시간을 표로 정리했고, 목소리 녹음 없이 자막만으로도 성립하도록 문장을 짧게 씀
|
||||
|
||||
## v4 → v5 변경 요약
|
||||
- **Q4-1 재구성**: 심사 공통 항목이 "창업활동자금과 AI 솔루션을 활용해 **2개월 내 MVP 제작이 가능한 수준인가**"임을 확인 → 0~3/4~6/7~12개월 구조를 **"이미 운영 중 + 2개월 안에 하는 일"** 중심으로 재편. Tasteby는 이 항목에서 "만들 수 있다"가 아니라 "이미 만들어 운영 중"으로 답할 수 있는 드문 경우
|
||||
- **Q3-2 축소**: 광고·캠페인 상품 수익원 **삭제**. 유명 큐레이터의 추천이 강점인 서비스에 노출 판매를 붙이면 Q3-1에서 비판한 기존 서비스와 같아지고 차별성이 무너짐 → "지금은 매출이 아니라 사용을 검증하는 단계"로 줄이고, 수익화 축은 크리에이터 파트너십으로 단일화
|
||||
- **Q4-2·Q8도 동반 수정**: 광고 상품 검증을 전제한 서술을 걷어내고 크리에이터 수익 배분 설계로 교체 (문서 전체에서 "노출을 팔지 않는다"가 일관되게 읽히도록)
|
||||
- 예약·주문 제휴는 **조건부**로만 남김 (테이블링·캐치테이블의 외부 제휴 프로그램 존재가 확인되지 않음 — 확인 전에는 수익원으로 단정하지 않는다)
|
||||
|
||||
### 심사 기준 (확인 결과, 2026-09-15)
|
||||
- 주최: 중소벤처기업부 대국민 창업 오디션. 일반/기술트랙 4,000명 + 로컬트랙 1,000명 선발, 진출 시 창업활동자금 200만 원 + 책임멘토링 + AI 바우처
|
||||
- 심사 3축: **도전의 진정성 / 사회적 가치(독창성·차별성) / 아이디어 구체성(BM 현실성·단계별 로드맵)**
|
||||
- 공통 항목: **2개월 내 MVP 제작 가능 수준인가**
|
||||
- 출처: modoo.or.kr, 멘토기관 80여 곳 평가지표 정리 자료
|
||||
|
||||
## v3 → v4 변경 요약
|
||||
- **Q8 완성**: 1차 지원서 원문이 `v1.md`(사용자 제공 원고)임을 확인 → 대괄호를 실제 1차 내용으로 채움. 1차의 실제 약점 4가지(제품 정의·수익모델 나열·근거 없는 수치·멘토 문항 오답)와 2차의 수정을 1:1로 대응시킴
|
||||
|
||||
## v2 → v3 변경 요약
|
||||
- **Q4-1 전면 수정**: "3개월에 식당 5,000곳"(현재의 10배, 달성 불가) → 현재 실측치(채널 6·영상 909·식당 500)에서 출발하는 배수 목표로 교체. 0~3개월 과제를 수량이 아니라 **LLM 미검증 1,071건 정리**로 재정의
|
||||
- **Q4-1에 사용자 현황 명시**: 공개 회원 모집을 아직 시작하지 않은 단계임을 밝히고, 4~6개월의 핵심 과제를 첫 사용자 집단 확보로 지정
|
||||
- **Q3-1·Q4-1에 해외 데이터 반영**: 일본 28곳 포함 해외 60여 곳이 이미 축적됨 → 일본 확장이 "구상"이 아니라 "이미 시작된 축적"임을 근거로 제시
|
||||
- **깨진 참조 링크 3개 제거** (`docs/design/705-…`, `docs/strategy/…`, `docs/design/711-…` — 리포에 존재하지 않음)
|
||||
|
||||
> 실측 출처: 2026-09-15 Admin 화면 및 `GET /api/restaurants?limit=100000` 조회. 상세는 `README.md` 실측 지표 표.
|
||||
|
||||
## Q1. 나의 아이디어를 한 줄로 소개해주세요. (필수 / 10~100자)
|
||||
|
||||
> 신뢰하는 미식 큐레이터의 영상 속 맛집을 찾아, 나의 다음 식사와 기록으로 연결하는 Tasteby
|
||||
|
||||
- v2 검증: 54자. 제출 화면의 실제 글자 수를 최종 확인한다.
|
||||
|
||||
## Q2. 아이디어를 떠올린 배경 이야기를 들려주세요. (필수 / 2,000자)
|
||||
|
||||
저는 맛집 영상을 보는 것을 좋아하지만, 막상 식사 약속이 잡히면 같은 문제를 반복해서 겪었습니다. "성시경 영상에서 본 그 국밥집이 어디였지?" 기억나는 것은 사람과 메뉴의 인상뿐이었습니다. 다시 영상을 찾아 자막을 넘기고, 식당 이름을 받아 적어 지도에 옮겨야 했습니다. 좋아하는 채널이 늘수록 저장한 정보도 늘었지만, 정작 필요한 순간에는 더 찾기 어려워졌습니다.
|
||||
|
||||
이 불편은 일본 여행에서 더 선명해졌습니다. 여행 전에 한국 미식 유튜버의 일본 맛집 영상을 여러 편 봤지만, 현지에서는 어느 영상의 어느 장면에 나온 식당인지 다시 찾는 데 시간이 들었습니다. 별점과 후기 수가 많은 식당은 쉽게 찾을 수 있었지만, 제가 실제로 궁금했던 것은 "내가 신뢰하는 이 사람이 왜 이곳을 골랐는가"였습니다. 영상, 지도, 메모앱이 각각 답의 일부만 갖고 있었습니다.
|
||||
|
||||
그래서 출발한 질문은 "맛집을 더 많이 모으려면 어떻게 해야 할까?"가 아니었습니다. **신뢰하는 사람의 선택을, 다음 식사를 고를 때 다시 쓸 수 있게 하려면 어떻게 해야 할까?**였습니다.
|
||||
|
||||
Tasteby는 미식 큐레이터의 영상·글 속 식당, 메뉴, 언급 맥락을 구조화해 지도와 탐색 화면에서 찾게 하는 서비스입니다. 사용자는 원본 콘텐츠로 다시 돌아가 맥락을 확인할 수 있고, 마음에 드는 곳은 자신의 찜과 비공개 메모에 남길 수 있습니다. 즉, Tasteby는 원본 영상을 대체하거나 익명 다수의 평가를 더 크게 만드는 서비스가 아니라, 흩어진 신뢰의 단서를 실제 외식 결정에 쓸 수 있게 연결하는 도구입니다.
|
||||
|
||||
AI는 이 일을 가능하게 하는 수단입니다. 영상 자막과 공개 정보를 바탕으로 식당 후보를 구조화하되, 원본 출처를 남기고 오류는 정정할 수 있게 설계합니다. 저는 "AI가 맛집을 대신 추천한다"보다 "사람이 쌓아 온 신뢰를 사용자가 다시 쓸 수 있게 한다"는 방향이 더 오래 갈 수 있다고 믿습니다. Tasteby는 좋은 한 끼를 찾는 순간과, 좋았던 한 끼를 다시 기억하는 순간을 하나의 경험으로 만들고자 합니다.
|
||||
|
||||
## Q3-1. 기존 제품 및 서비스 대비 차별점과 어떤 문제를 해결할 수 있나요? (필수 / 2,000자)
|
||||
|
||||
Tasteby는 또 하나의 맛집 순위 서비스가 아닙니다. 출발점이 "평점이 높은 곳은 어디인가?"가 아니라 **"내가 신뢰하는 사람이 어느 콘텐츠에서, 어떤 메뉴를, 왜 언급했는가?"**이기 때문입니다.
|
||||
|
||||
기존 맛집 서비스는 대체로 다수 이용자의 별점·후기, 예약 가능 여부, 지역 검색을 중심으로 설계돼 있습니다. 이 방식은 넓은 선택지를 빠르게 보여 주는 데 유용하지만, 영상을 보고 특정 사람의 선택을 기억한 사용자에게는 두 가지 공백이 남습니다. 첫째, 영상 속 식당의 이름·주소·메뉴가 콘텐츠 안에 흩어져 있어 나중에 다시 찾기 어렵습니다. 둘째, 평균 별점만으로는 왜 그 사람이 그 식당을 언급했는지, 내가 오늘 갈 이유가 있는지 판단하기 어렵습니다.
|
||||
|
||||
Tasteby의 차별점은 세 가지입니다.
|
||||
|
||||
첫째, **출처가 있는 발견**입니다. 식당을 보여 줄 때 원본 콘텐츠와 메뉴·언급 맥락을 함께 연결합니다. 사용자는 Tasteby의 요약만 믿을 필요 없이 원본으로 돌아가 확인할 수 있습니다. 추천인지 단순 언급인지, 협찬 또는 정정 정보가 확인되는 경우에는 이를 구분해 보이는 방향으로 신뢰를 설계합니다.
|
||||
|
||||
둘째, **분야별 큐레이터의 선택을 탐색 기준으로 사용**합니다. 사용자는 무작위 목록이 아니라 자신이 신뢰하는 미식 큐레이터, 먹고 싶은 메뉴, 갈 지역을 함께 놓고 후보를 좁힐 수 있습니다. 이는 "유명해서"가 아니라 특정 음식과 상황을 꾸준히 다뤄 온 사람의 관점을 발견의 출발점으로 삼는 방식입니다.
|
||||
|
||||
셋째, **개인의 맛 기억을 기본 비공개로 보존**합니다. 사용자는 방문 뒤 좋았던 이유와 다음에 갈 조건을 자기 메모로 남길 수 있습니다. 공개 리뷰를 많이 쓰게 하는 대신, 먼저 나를 위한 기록이 다음 선택에 다시 쓰이도록 하는 것이 목표입니다. 나중에 사용자가 원할 때만 일부 후보를 동행에게 공유할 수 있으며, 비공개 메모는 공유되지 않습니다.
|
||||
|
||||
이 구조는 국내에만 적용되는 것이 아닙니다. 현재도 한국 큐레이터가 다룬 일본·미국·싱가포르 등 해외 식당 60여 곳이 같은 방식으로 쌓이고 있습니다. 여행지에서 익명 리뷰를 처음부터 다시 읽는 대신, 이미 신뢰하는 사람의 선택을 그대로 꺼내 쓸 수 있다는 뜻입니다.
|
||||
|
||||
Tasteby가 해결하려는 문제는 정보 부족이 아니라 **신뢰할 만한 정보를 다시 쓸 수 없는 문제**입니다. 음식 콘텐츠를 보는 사람은 다음 식사를 더 쉽게 결정하고, 크리에이터는 자신의 콘텐츠가 일회성 조회를 넘어 정정 가능하고 탐색 가능한 아카이브로 이어질 수 있습니다. AI는 이 구조를 빠르게 만들지만, 경쟁력의 핵심은 AI 자체가 아니라 출처를 보존하고 개인의 선택으로 이어 주는 제품 경험입니다.
|
||||
|
||||
## Q3-2. 어떻게 수익을 창출할 계획인가요? (선택 / 2,000자)
|
||||
|
||||
Tasteby는 지금 매출을 만드는 단계가 아니라, 사람들이 실제로 다시 쓰는지 검증하는 단계입니다. 그래서 수익 모델도 크게 벌이기보다 **서비스의 강점을 훼손하지 않는 방식**을 먼저 정해 두었습니다.
|
||||
|
||||
먼저 하지 않기로 한 것이 있습니다. **검색 결과나 추천 순위를 판매하지 않습니다.** Tasteby를 찾는 이유는 신뢰하는 사람이 고른 집을 보기 위해서입니다. 그 화면에 돈을 낸 식당이 섞이는 순간, 옆에 있는 진짜 추천까지 의심받습니다. 기존 맛집 서비스가 잃은 것이 정확히 그 신뢰이므로, 노출을 파는 방식은 처음부터 배제합니다.
|
||||
|
||||
수익의 축은 **크리에이터 파트너십**입니다. 미식 크리에이터에게 채널 공식 페이지를 제공해 영상 속 식당이 검색 가능한 아카이브로 남게 하고, 그 페이지에서 발생한 성과를 크리에이터와 나눕니다. 크리에이터가 이미 영상에서 추천한 가게를 다루는 구조이므로 추천의 순수성이 유지되고, 크리에이터가 수익을 얻으면 Tasteby를 알릴 이유도 함께 생깁니다. 광고와는 방향이 반대입니다.
|
||||
|
||||
사용자가 스스로 예약이나 주문을 원할 때 연결하는 제휴 수수료는 다음 단계의 선택지로 둡니다. 현재 서비스에는 예약 링크가 연결된 식당이 이미 300곳 이상 있지만, 예약 플랫폼의 제휴 조건을 확인하기 전까지는 수익원으로 단정하지 않겠습니다.
|
||||
|
||||
12개월 안에 큰 매출을 약속드리지는 않겠습니다. 이 기간의 목표는 크리에이터 3팀과 실제 파트너십을 맺어 수익 배분 구조를 한 번 돌려 보는 것이고, 본격적인 수익화는 사용자가 반복해서 돌아온다는 증거가 쌓인 뒤의 일입니다.
|
||||
|
||||
## Q4-1. 아이디어를 어떻게 사업화 하실 계획이신가요? (필수 / 2,000자)
|
||||
|
||||
**Tasteby는 기획안이 아니라 이미 동작하는 서비스입니다.** www.tasteby.net 에서 운영 중이며, 2026년 9월 기준 등록 채널 6곳, 수집 영상 909편에서 추출해 좌표까지 연결한 식당 500곳이 들어 있습니다. 그중 일본 28곳을 비롯한 해외 식당이 60여 곳이고, 예약 링크가 연결된 식당도 300곳이 넘습니다. 큐레이터·지역·메뉴로 좁혀 찾는 탐색, 지도 기반 발견, 회원·찜·공개 리뷰·비공개 메모까지 사용자가 한 바퀴 도는 흐름이 모두 구현돼 있습니다. 저는 이 전부를 Spring Boot와 Next.js로 직접 설계하고 구현해 클라우드에 배포했습니다.
|
||||
|
||||
그래서 저에게 2개월은 무언가를 처음 만드는 기간이 아니라, **이미 만든 것을 사람들 앞에 내놓는 기간**입니다.
|
||||
|
||||
**2개월 안에 하는 일은 세 가지입니다.** 첫째, 데이터의 정확도를 끝까지 올리겠습니다. 현재 LLM 검증을 거치지 않은 영상-식당 연결이 1,071건 남아 있습니다. AI 솔루션을 활용해 이를 모두 검증하고, 잘못 연결된 항목을 정리해 출처가 확인된 식당만 노출하겠습니다. 둘째, 채널을 10곳으로 늘려 식당 1,500곳 규모를 만들되 정확도 기준을 통과한 것만 셈에 넣겠습니다. 셋째, 아직 시작하지 않은 공개 사용자 모집을 열고, `발견 → 원본 확인 → 후보 저장 → 재방문`이 실제로 이어지는지 계측하겠습니다. 2개월 뒤에 제가 보여드릴 것은 기능 시연이 아니라, **검증된 데이터 위에서 사람들이 실제로 어떻게 움직였는가** 입니다.
|
||||
|
||||
**그 다음은 신뢰를 파트너십으로 넓히는 단계입니다.** 미식 크리에이터에게 오래된 영상이 검색 가능한 아카이브로 남는다는 가치를 제안해 6개월 안에 3팀과 협력하겠습니다. 이때 필요한 계약·저작권·표기 기준은 책임멘토의 도움을 받고자 합니다. 12개월 시점에는 이미 쌓여 있는 일본 데이터를 바탕으로 여행 사용 맥락을 검증하고, 찜한 후보를 동행과 함께 고르는 공유 기능을 더하겠습니다.
|
||||
|
||||
가장 큰 위험은 기술이 아니라 신뢰입니다. 원본 링크를 반드시 보존하고, 협찬과 정정 상태를 관리하며, 사용자의 비공개 메모는 어떤 경우에도 광고나 외부 판매에 쓰지 않겠습니다. "더 많은 식당"이 아니라 "다시 쓰이는 신뢰"를 증명하는 것이 Tasteby의 사업화입니다.
|
||||
|
||||
> 제출 전 사실 확인: 실측치(채널 6·영상 909·식당 500·미검증 1,071·해외 60여·예약링크 300여)는 2026-09-15 기준. 제출일에 재조회해 갱신한다.
|
||||
|
||||
## Q4-2. 책임멘토를 통해 어떤 도움을 받고 싶은가요? (선택 / 2,000자)
|
||||
|
||||
저는 Tasteby의 제품과 기술 구현은 직접 추진해 왔지만, 다음 단계에서 필요한 것은 개발 조언보다 **신뢰를 훼손하지 않는 시장 진입과 계약의 기준**입니다. 책임멘토에게 네 가지 도움을 받고 싶습니다.
|
||||
|
||||
첫째, 크리에이터 파트너십의 실무입니다. Tasteby는 타인의 콘텐츠를 대신 소비시키는 서비스가 아니라 원본으로 다시 연결하는 서비스여야 합니다. 큐레이터·매니저에게 어떤 가치 제안을 해야 하는지, 출처·초상·인용·협찬 표기를 어떤 계약과 운영 절차로 정리해야 하는지 조언을 받고 싶습니다.
|
||||
|
||||
둘째, 신뢰를 해치지 않는 수익 구조의 설계입니다. Tasteby는 검색 결과나 추천 순위를 판매하지 않기로 했기 때문에, 남는 길은 크리에이터와 함께 버는 구조입니다. 채널 공식 페이지의 성과를 어떤 기준으로 나눠야 크리에이터와 서비스 모두에게 지속 가능한지, 예약·주문 연결처럼 사용자가 먼저 원할 때만 작동하는 수익원은 어떤 조건에서 성립하는지 조언을 받고 싶습니다.
|
||||
|
||||
셋째, 초기 사용자 획득 전략입니다. 검색·커뮤니티·콘텐츠 중 어떤 좁은 시장에서 출처 탐색과 후보 저장이 실제로 반복되는지, 작은 예산으로 무엇을 먼저 검증해야 하는지에 대한 피드백이 필요합니다. '바이럴'이나 조회 수가 아니라 재방문과 결정 행동으로 판단하는 방법을 배우고 싶습니다.
|
||||
|
||||
넷째, 해외 확장 우선순위입니다. 일본 여행 콘텐츠는 분명한 사용 사례이지만, 국내에서 어떤 데이터 품질과 파트너십 기준을 먼저 증명해야 하는지, 다국어·현지 정보·권리 이슈를 어떤 순서로 풀어야 하는지 검토받고 싶습니다.
|
||||
|
||||
멘토링을 통해 막연한 인맥 소개보다, 파트너십·수익·유통에서 반복 가능한 의사결정 기준을 얻고 싶습니다. 이를 바탕으로 1인 개발자가 만든 MVP를 신뢰할 수 있는 소비자 서비스와 지속 가능한 사업으로 확장하겠습니다.
|
||||
|
||||
## Q5. 나의 아이디어를 소개하는 영상을 링크로 제출해주세요. (선택 / 유튜브 링크만)
|
||||
|
||||
**권장: 제출한다.** 75~90초 분량으로 아래 흐름을 사용한다.
|
||||
|
||||
1. 0~15초 — "그 영상의 그 식당, 어디였지?"라는 개인 경험과 재검색 장면
|
||||
2. 15~40초 — Tasteby에서 큐레이터·식당·메뉴·원본을 연결해 찾는 실제 화면
|
||||
3. 40~60초 — 찜과 비공개 메모, 동행과 후보를 고르는 공유 카드의 가치
|
||||
4. 60~80초 — AI는 정보를 구조화하고, Tasteby는 사람의 신뢰를 다시 쓰게 한다는 차별점
|
||||
5. 80~90초 — 12개월 검증 목표와 멘토링 요청
|
||||
|
||||
> **촬영 대본: `q5-video-script.md`** (85초 9컷, 화면·자막·시간 표)
|
||||
> 제출 전 입력: `[YouTube URL]`
|
||||
> 제작 원칙: Tasteby 자체 화면·직접 제작한 도식만 사용한다. 타인의 유튜브 영상·썸네일·음원을 무단 삽입하지 않는다.
|
||||
|
||||
## Q6. 사업 분야를 선택해주세요. (필수 / 드롭다운)
|
||||
|
||||
**제출 전 실제 선택지 확인 후 선택한다.**
|
||||
|
||||
1순위는 `AI·데이터`다. Tasteby의 사용자 가치는 외식 발견이지만, 영상·글에서 식당 정보를 구조화하고 출처 기반으로 탐색하게 하는 핵심 실행 수단이 AI·데이터이기 때문이다. 해당 선택지가 없으면 2순위는 `플랫폼/O2O`, 그다음은 `푸드테크`다. 예약·배달 거래가 현재 핵심이 아니므로 관광·여행은 일본 베타 이후의 보조 분야로 둔다.
|
||||
|
||||
## Q7. 지원자의 현재 창업 여부를 알려주세요. (필수 / 택1)
|
||||
|
||||
**법적 사실 확인 전 선택하지 않는다.**
|
||||
|
||||
| 확인 결과 | 선택 |
|
||||
|---|---|
|
||||
| 본인 명의 사업자/법인의 창업일이 기준 기간에 없거나, 기창업자 요건에 해당하지 않음 | `예비창업자` |
|
||||
| 창업일이 2019-08-21~2026-08-20이고 Tasteby가 기존 사업과 다른 이종 창업 아이템임 | `기창업자` |
|
||||
|
||||
MVP를 개발하거나 도메인을 운영했다는 사실만으로 Q7을 판단하지 않는다. 사업자등록·법인 설립·공고의 세부 기준을 제출 전에 확인한다.
|
||||
|
||||
## Q8. 2차 지원서에서는 1차 지원서보다 어떤 점이 더 개선되었나요? (선택 / 재도전 가점)
|
||||
|
||||
1차에서는 Tasteby를 "유튜브 맛집 영상에서 AI가 식당 정보를 자동으로 추출해 지도에 모아주는 서비스"로 설명했습니다. 타겟 규모와 기술 구성, 12개월 로드맵을 제시했지만 지원서를 다시 읽어 보니 네 가지가 비어 있었습니다. 제품을 정보 수집 기능으로만 설명했고, 수익 모델이 몇 줄의 나열에 그쳤으며, 목표 수치에 근거가 없었고, 멘토링 문항에는 멘토에게 받고 싶은 도움 대신 자금 사용 계획을 적었습니다.
|
||||
|
||||
**첫째, 제품의 정의를 바꿨습니다.** "AI가 맛집을 모아준다"에서 "신뢰하는 큐레이터의 출처로 발견하고, 내 비공개 기록으로 남겨 다음 식사에 다시 쓰고, 필요한 후보만 동행과 공유한다"는 사용 흐름으로 다시 썼습니다. 경쟁력은 수집 기술이 아니라 사용자가 신뢰를 다시 쓰게 만드는 구조에 있다고 판단했기 때문입니다.
|
||||
|
||||
**둘째, 수익 모델에서 하지 않을 것을 먼저 정했습니다.** 1차의 "유튜버 파트너십·식당 제휴·장기 데이터 사업" 나열 대신, 검색 결과와 추천 순위는 판매하지 않는다는 원칙을 세웠습니다. 신뢰하는 사람이 고른 집을 보러 온 화면에 돈을 낸 가게가 섞이면 진짜 추천까지 의심받고, 그것이 기존 맛집 서비스가 신뢰를 잃은 이유이기 때문입니다. 대신 이미 영상에서 추천된 가게를 다루는 크리에이터 파트너십을 수익의 축으로 단일화했습니다.
|
||||
|
||||
**셋째, 목표 수치를 실측에서 다시 세웠습니다.** 1차에 적은 "3개월 내 식당 5,000곳"은 현재 500곳 기준으로 10배여서 달성 가능한 계획이 아니었습니다. 2차에서는 채널 6곳·영상 909편·식당 500곳이라는 현재 값을 밝히고, 0~3개월의 과제를 수량 확대가 아니라 아직 검증되지 않은 영상-식당 연결 1,071건을 정리하는 일로 바꿨습니다. 공개 회원 모집을 아직 시작하지 않았다는 사실도 그대로 적었습니다.
|
||||
|
||||
**넷째, 멘토링 문항을 질문에 맞게 다시 썼습니다.** 자금 사용 계획 대신 크리에이터 계약 실무, B2B 상품 검증, 초기 사용자 획득, 해외 확장 우선순위 네 가지로 구체화했습니다.
|
||||
|
||||
1차가 "무엇을 만들 수 있는가"에 대한 답이었다면, 2차는 "누가 왜 다시 쓰고, 어떤 순서로 검증하며, 어떻게 사업이 되는가"에 대한 답입니다. 그사이 서비스도 멈춰 있지 않았습니다. 지역 표시 계층화, 언급이 적은 식당을 걸러내는 필터, 해외 식당의 국내 전용 예약 버튼 제거처럼 신뢰와 정확도에 관한 개선을 계속 반영해 왔습니다.
|
||||
|
||||
## Q9. 아이디어를 사업화 시킬 수 있는 본인의 역량을 알려주세요. (선택 / 2,000자)
|
||||
|
||||
Tasteby의 가장 큰 강점 중 하나는 아이디어를 설명하는 데서 멈추지 않고, 제품으로 만들고 운영 가능한 형태로 옮겨 왔다는 점입니다. 저는 1인 풀스택 개발자로서 문제 정의부터 데이터 구조, 백엔드·프론트엔드 구현, AI 처리 파이프라인, 배포 환경까지 직접 설계하고 연결해 왔습니다.
|
||||
|
||||
Tasteby에서는 Spring Boot와 Java 기반의 서비스 로직, Next.js 기반의 사용자 화면, Oracle 23ai 벡터 데이터베이스와 Redis를 활용한 데이터 처리 구조를 구성했습니다. 영상·글에서 식당 후보 정보를 구조화하고, 지오코딩·지도·검색으로 사용자가 다시 찾을 수 있게 만드는 파이프라인도 직접 만들었습니다. 기술을 개별 기능으로 쌓기보다, "출처를 찾는다 → 후보를 저장한다 → 방문 뒤 기억한다 → 다음 선택에 다시 쓴다"는 한 사용 흐름이 완성되도록 설계한 경험이 있습니다.
|
||||
|
||||
저의 실행 방식은 작은 가설을 빠르게 제품으로 옮기고, 실제 사용 행동으로 다음 우선순위를 정하는 것입니다. 예를 들어 Tasteby의 비공개 메모는 리뷰를 많이 받기 위한 기능이 아니라, 사용자가 좋았던 경험을 다음 외식에 다시 쓰게 하기 위한 기능입니다. 찜 공유 역시 전체 취향을 공개하는 기능이 아니라, 사용자가 고른 후보만 동행과 함께 결정하게 하는 기능으로 분리했습니다. 이처럼 기술의 가능성보다 사용자의 신뢰와 권한을 먼저 설계하는 것이 저의 제품 역량입니다.
|
||||
|
||||
또한 혼자서도 기획·개발·운영을 연결할 수 있지만, 모든 것을 혼자 해결하려 하지 않습니다. 크리에이터 계약, 저작권·표기, 초기 B2B 영업, 해외 확장은 멘토와 파트너의 전문성이 필요한 영역으로 분명히 인식하고 있습니다. 저는 빠르게 만들 수 있는 실행력과, 모르는 영역을 검증 가능한 질문으로 바꾸는 운영 방식을 바탕으로 Tasteby를 사업으로 성장시키겠습니다.
|
||||
|
||||
> 제출 전 보강 후보: 공개 가능한 직장 경력, 이전 프로젝트, 수상·자격, 서비스 운영 수치가 있으면 사실 확인 뒤 한 단락만 추가한다.
|
||||
|
||||
## Q10. 함께하는 팀원이 있다면 본인을 제외한 팀원 명수를 알려주세요. (선택 / 드롭다운)
|
||||
|
||||
`팀원 없음`
|
||||
|
||||
현재는 1인 창업자로 제품을 직접 개발·운영한다. 다만 법무·크리에이터 파트너십·B2B 영업은 외부 전문가 및 멘토와 보완할 계획이다.
|
||||
|
||||
## Q11. 내 아이디어를 사람들에게 자랑해보세요. (선택 / 홈페이지 공개 + 좋아요)
|
||||
|
||||
**"그 영상에서 봤던 그 집, 어디였더라?"**
|
||||
|
||||
맛집 영상을 즐겨 보는 분이라면 한 번쯤 겪어보셨을 겁니다. 분명 봤는데, 막상 약속이 잡히면 어느 영상의 어느 장면이었는지 다시 뒤져야 하죠. 저도 그랬습니다. 일본 여행을 가서는 도쿄 한복판에 서서 영상을 되감고 있었습니다.
|
||||
|
||||
그래서 만들었습니다. **Tasteby**는 내가 믿는 미식 유튜버들이 다녀간 가게를 AI가 영상에서 찾아내 지도 위에 모아줍니다. 가게를 누르면 그 사람이 어떤 영상에서 뭐라고 했는지 그대로 나오고, 궁금하면 원본 영상으로 바로 돌아갈 수 있습니다.
|
||||
|
||||
별점 평균이 아니라 **사람**이 기준입니다. 오늘 떡볶이가 당기면 분식만 파고든 채널이 검증한 집으로, 특별한 날이면 파인다이닝을 다루는 채널이 고른 집으로 갑니다.
|
||||
|
||||
지금 채널 6곳, 영상 909편에서 찾아낸 식당 500곳이 올라가 있습니다. 일본 가게도 조금씩 쌓이는 중입니다. 기획부터 개발, 배포까지 혼자 만들었고, 지금도 매주 고치고 있습니다.
|
||||
|
||||
**www.tasteby.net** — 가입 없이 바로 둘러보실 수 있습니다.
|
||||
|
||||
> 게시 전: 대표 스크린샷 1장을 함께 올린다. 숫자는 게시일 기준으로 재확인한다.
|
||||
|
||||
## Q12. 서약서 동의 (필수)
|
||||
|
||||
제출 직전에 아래를 각각 읽고 동의한다.
|
||||
|
||||
- 참여 서약서
|
||||
- 본인 아이디어 확인 서약서
|
||||
- 비밀유지 서약서
|
||||
|
||||
## 사진 배분 계획 (전체 10장 제한)
|
||||
|
||||
| 문항 | 장수 | 권장 이미지 | 심사에서 보여 줄 사실 |
|
||||
|------|---:|---|---|
|
||||
| Q2 | 1 | 직접 만든 `영상 속 정보 → Tasteby 출처·지도 → 다음 식사` 흐름 도식 | 왜 이 서비스가 필요한가 |
|
||||
| Q3-1 | 3 | 지도 탐색, 식당 상세의 원본/메뉴 근거, 찜·비공개 메모 화면 | 출처·개인 기록의 차별점 |
|
||||
| Q4-1 | 2 | 데이터 처리·정정 흐름 도식, 12개월 로드맵 | 이미 만든 것과 다음 검증 순서 |
|
||||
| Q9 | 1 | 실제 서비스 아키텍처 또는 개발·배포 흐름 | 1인 실행 역량 |
|
||||
| Q11 | 1 | 모바일 또는 데스크톱 대표 화면 한 장 | 공개 소개의 첫 인상 |
|
||||
| 예비 | 2 | 수신자 공유 카드, 모바일 탐색 화면 | 심사 코멘트 대응 또는 품질이 높은 화면 교체 |
|
||||
|
||||
총 8장을 기본으로 사용하고 2장은 예비로 남긴다. 모든 화면은 제출일 기준 실제 동작·표현과 일치해야 하며, 원본 영상 캡처·타인 음식 사진은 사용권을 확인하지 못하면 사용하지 않는다.
|
||||
117
frontend/__tests__/RestaurantDetail.test.tsx
Normal file
117
frontend/__tests__/RestaurantDetail.test.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* #545 — 해외 식당 상세에서 테이블링/캐치테이블 예약 버튼 숨김 회귀 테스트.
|
||||
* 좌표 기반(isKoreaRestaurant) 판정으로 국내/해외 식당에서 버튼 노출 여부가
|
||||
* 올바르게 갈리는지 검증한다.
|
||||
*/
|
||||
import { act, render, screen } from "@testing-library/react";
|
||||
import RestaurantDetail from "@/components/RestaurantDetail";
|
||||
import type { Restaurant } from "@/lib/api";
|
||||
|
||||
// 컴포넌트 마운트 시 발생하는 비동기 데이터 로딩(영상/리뷰 등)을 플러시해
|
||||
// act() 경고 없이 안정적으로 렌더 결과를 검증한다.
|
||||
async function flush() {
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
jest.mock("@/lib/api", () => ({
|
||||
getToken: jest.fn(() => null),
|
||||
api: {
|
||||
getRestaurantVideos: jest.fn(() => Promise.resolve([])),
|
||||
getFavoriteStatus: jest.fn(() => Promise.resolve({ favorited: false })),
|
||||
getReviews: jest.fn(() =>
|
||||
Promise.resolve({ reviews: [], avg_rating: null, review_count: 0 })
|
||||
),
|
||||
getMemo: jest.fn(() => Promise.resolve(null)),
|
||||
},
|
||||
}));
|
||||
|
||||
function makeRestaurant(overrides: Partial<Restaurant>): Restaurant {
|
||||
return {
|
||||
id: "r1",
|
||||
name: "테스트 식당",
|
||||
address: null,
|
||||
region: null,
|
||||
latitude: 37.5,
|
||||
longitude: 127.0,
|
||||
cuisine_type: null,
|
||||
price_range: null,
|
||||
google_place_id: null,
|
||||
tabling_url: null,
|
||||
catchtable_url: null,
|
||||
business_status: null,
|
||||
rating: null,
|
||||
rating_count: null,
|
||||
phone: null,
|
||||
website: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("RestaurantDetail — #545 해외 식당 예약 버튼 숨김", () => {
|
||||
it("국내 식당(좌표 기반)이면 테이블링/캐치테이블 버튼이 보인다", async () => {
|
||||
const restaurant = makeRestaurant({
|
||||
latitude: 37.5665,
|
||||
longitude: 126.978, // 서울
|
||||
tabling_url: "https://tabling.example.com/1",
|
||||
catchtable_url: "https://catchtable.example.com/1",
|
||||
});
|
||||
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
|
||||
await flush();
|
||||
expect(screen.getByText("테이블링에서 줄서기")).toBeInTheDocument();
|
||||
expect(screen.getByText("캐치테이블에서 예약하기")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("해외 식당(좌표가 KR bbox 밖)이면 두 버튼 모두 숨겨진다 (대표 발견 케이스)", async () => {
|
||||
const restaurant = makeRestaurant({
|
||||
latitude: 13.7563,
|
||||
longitude: 100.5018, // 방콕
|
||||
tabling_url: "https://tabling.example.com/1",
|
||||
catchtable_url: "https://catchtable.example.com/1",
|
||||
});
|
||||
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
|
||||
await flush();
|
||||
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("해외 식당이어도 예약 URL이 없으면 애초에 버튼이 없다 (회귀 없음 확인)", async () => {
|
||||
const restaurant = makeRestaurant({
|
||||
latitude: 35.6762,
|
||||
longitude: 139.6503, // 도쿄
|
||||
tabling_url: null,
|
||||
catchtable_url: null,
|
||||
});
|
||||
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
|
||||
await flush();
|
||||
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("좌표 없는 구 데이터는 region으로 fallback되어 국내로 간주된다 (기존 동작 유지)", async () => {
|
||||
const restaurant = makeRestaurant({
|
||||
latitude: undefined as unknown as number,
|
||||
longitude: undefined as unknown as number,
|
||||
region: null,
|
||||
tabling_url: "https://tabling.example.com/1",
|
||||
catchtable_url: null,
|
||||
});
|
||||
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
|
||||
await flush();
|
||||
expect(screen.getByText("테이블링에서 줄서기")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("예약 URL이 'NONE' 문자열이면 국내 식당이어도 버튼이 없다 (기존 게이트 유지)", async () => {
|
||||
const restaurant = makeRestaurant({
|
||||
latitude: 37.5665,
|
||||
longitude: 126.978,
|
||||
tabling_url: "NONE",
|
||||
catchtable_url: "NONE",
|
||||
});
|
||||
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
|
||||
await flush();
|
||||
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
36
frontend/__tests__/filters.test.ts
Normal file
36
frontend/__tests__/filters.test.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* #533 — passesMinMentions() 순수 함수 단위 테스트.
|
||||
* 설계서: docs/design/533-min-mentions-filter/README.md
|
||||
*/
|
||||
import { passesMinMentions } from "@/lib/filters";
|
||||
|
||||
describe("passesMinMentions", () => {
|
||||
it("minMentions=0(기본)이면 필터 미적용 — 항상 true", () => {
|
||||
expect(passesMinMentions(0, 0)).toBe(true);
|
||||
expect(passesMinMentions(null, 0)).toBe(true);
|
||||
expect(passesMinMentions(100, 0)).toBe(true);
|
||||
});
|
||||
|
||||
it("음수 minMentions도 필터 미적용으로 취급한다", () => {
|
||||
expect(passesMinMentions(0, -1)).toBe(true);
|
||||
});
|
||||
|
||||
it("video_count 가 minMentions 미만이면 제외(false)", () => {
|
||||
expect(passesMinMentions(1, 2)).toBe(false);
|
||||
expect(passesMinMentions(0, 1)).toBe(false);
|
||||
});
|
||||
|
||||
it("video_count 가 minMentions 와 같으면 포함(경계값 포함)", () => {
|
||||
expect(passesMinMentions(2, 2)).toBe(true);
|
||||
});
|
||||
|
||||
it("video_count 가 minMentions 초과면 포함", () => {
|
||||
expect(passesMinMentions(5, 2)).toBe(true);
|
||||
});
|
||||
|
||||
it("video_count 가 null/undefined(미산정)이면 0으로 간주한다", () => {
|
||||
expect(passesMinMentions(null, 2)).toBe(false);
|
||||
expect(passesMinMentions(undefined, 2)).toBe(false);
|
||||
expect(passesMinMentions(null, 0)).toBe(true);
|
||||
});
|
||||
});
|
||||
44
frontend/__tests__/region.test.ts
Normal file
44
frontend/__tests__/region.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* #532 — formatRegion() 순수 함수 단위 테스트.
|
||||
* 설계서: docs/design/532-region-display/README.md
|
||||
*/
|
||||
import { formatRegion } from "@/lib/region";
|
||||
|
||||
describe("formatRegion", () => {
|
||||
it("falsy 입력은 빈 문자열", () => {
|
||||
expect(formatRegion("")).toBe("");
|
||||
expect(formatRegion(null)).toBe("");
|
||||
expect(formatRegion(undefined)).toBe("");
|
||||
});
|
||||
|
||||
it("파이프 구분 지역을 계층(breadcrumb)으로 변환한다", () => {
|
||||
expect(formatRegion("한국|서울|강남구")).toBe("한국 › 서울 › 강남구");
|
||||
});
|
||||
|
||||
it("'null' 토큰(대소문자 무시)은 제거한다", () => {
|
||||
expect(formatRegion("일본|null")).toBe("일본");
|
||||
expect(formatRegion("일본|NULL")).toBe("일본");
|
||||
});
|
||||
|
||||
it("빈 토큰은 제거한다", () => {
|
||||
expect(formatRegion("한국||관악구")).toBe("한국 › 관악구");
|
||||
});
|
||||
|
||||
it("더미 토큰 '나라'는 제거한다", () => {
|
||||
expect(formatRegion("나라|서울")).toBe("서울");
|
||||
});
|
||||
|
||||
it("단일 토큰은 그대로 반환한다", () => {
|
||||
expect(formatRegion("한국")).toBe("한국");
|
||||
});
|
||||
|
||||
it("모든 토큰이 더미/빈 값이면 빈 문자열", () => {
|
||||
expect(formatRegion("한국|")).toBe("한국");
|
||||
expect(formatRegion("|")).toBe("");
|
||||
expect(formatRegion("나라|null|")).toBe("");
|
||||
});
|
||||
|
||||
it("토큰 앞뒤 공백은 trim 된다", () => {
|
||||
expect(formatRegion(" 한국 | 서울 ")).toBe("한국 › 서울");
|
||||
});
|
||||
});
|
||||
@@ -15,6 +15,7 @@ import MyReviewsList from "@/components/MyReviewsList";
|
||||
import BottomSheet from "@/components/BottomSheet";
|
||||
import FilterSheet, { FilterOption } from "@/components/FilterSheet";
|
||||
import { getCuisineIcon, getPhosphorCuisineIcon } from "@/lib/cuisine-icons";
|
||||
import { passesMinMentions } from "@/lib/filters";
|
||||
import Icon from "@/components/Icon";
|
||||
import FoodIcon from "@/components/FoodIcon";
|
||||
import * as PhosphorIcons from "@phosphor-icons/react";
|
||||
@@ -196,6 +197,7 @@ export default function Home() {
|
||||
const [channelFilter, setChannelFilter] = useState("");
|
||||
const [cuisineFilter, setCuisineFilter] = useState("");
|
||||
const [priceFilter, setPriceFilter] = useState("");
|
||||
const [minMentions, setMinMentions] = useState(0); // #533 — 의미있는 언급 N회 미만 식당 제외 (0=전체)
|
||||
const [viewMode, setViewMode] = useState<"map" | "list">("list");
|
||||
const [mobileTab, setMobileTab] = useState<"home" | "list" | "nearby" | "favorites" | "profile">("home");
|
||||
const [showMobileFilters, setShowMobileFilters] = useState(false);
|
||||
@@ -248,6 +250,7 @@ export default function Home() {
|
||||
if (channelFilter && !(r.channels || []).includes(channelFilter)) return false;
|
||||
if (cuisineFilter && !matchCuisineFilter(r.cuisine_type, cuisineFilter)) return false;
|
||||
if (priceFilter && !matchPriceGroup(r.price_range, priceFilter)) return false;
|
||||
if (!passesMinMentions(r.video_count, minMentions)) return false;
|
||||
if (countryFilter) {
|
||||
const parsed = parseRegion(r.region);
|
||||
if (!parsed || parsed.country !== countryFilter) return false;
|
||||
@@ -271,7 +274,7 @@ export default function Home() {
|
||||
if (da !== db) return da - db;
|
||||
return (b.rating || 0) - (a.rating || 0);
|
||||
});
|
||||
}, [restaurants, isSearchResult, channelFilter, cuisineFilter, priceFilter, countryFilter, cityFilter, districtFilter, boundsFilterOn, mapBounds, userLoc]);
|
||||
}, [restaurants, isSearchResult, channelFilter, cuisineFilter, priceFilter, minMentions, countryFilter, cityFilter, districtFilter, boundsFilterOn, mapBounds, userLoc]);
|
||||
|
||||
// FilterSheet option builders
|
||||
const cuisineOptions = useMemo<FilterOption[]>(() => {
|
||||
@@ -366,6 +369,7 @@ export default function Home() {
|
||||
setChannelFilter("");
|
||||
setCuisineFilter("");
|
||||
setPriceFilter("");
|
||||
setMinMentions(0);
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
@@ -385,10 +389,8 @@ export default function Home() {
|
||||
const handleSelectRestaurant = useCallback((r: Restaurant) => {
|
||||
setSelected(r);
|
||||
setShowDetail(true);
|
||||
// 지도가 선택 식당으로 이동/줌인 — 객체 새로 만들어 flyTo effect 매번 트리거
|
||||
if (r.latitude != null && r.longitude != null) {
|
||||
setRegionFlyTo({ lat: r.latitude, lng: r.longitude, zoom: 16 });
|
||||
}
|
||||
// selected 변경 자체가 MapView 내부의 useEffect에서 중앙 이동을 처리.
|
||||
// (flyTo를 같이 set하면 줌 16으로 강제되어 클러스터 expansion 후 마커 클릭 시 다시 묶임)
|
||||
}, []);
|
||||
|
||||
const handleCloseDetail = useCallback(() => {
|
||||
@@ -479,6 +481,7 @@ export default function Home() {
|
||||
setChannelFilter("");
|
||||
setCuisineFilter("");
|
||||
setPriceFilter("");
|
||||
setMinMentions(0);
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
@@ -820,9 +823,23 @@ export default function Home() {
|
||||
<option key={g.label} value={g.label}>{g.label}</option>
|
||||
))}
|
||||
</select>
|
||||
{(cuisineFilter || priceFilter) && (
|
||||
<div className="w-px h-3 bg-gray-200 dark:bg-gray-700" />
|
||||
<select
|
||||
value={minMentions}
|
||||
onChange={(e) => { setMinMentions(Number(e.target.value)); if (Number(e.target.value)) setBoundsFilterOn(false); }}
|
||||
className={`bg-transparent border-none outline-none cursor-pointer pr-1 ${
|
||||
minMentions > 0 ? "text-brand-600 dark:text-brand-400 font-medium" : "text-gray-500 dark:text-gray-400"
|
||||
}`}
|
||||
title="영상에서 충분히 언급된(관련도 높은) 식당만 보기"
|
||||
>
|
||||
<option value={0}>언급</option>
|
||||
<option value={2}>2회+</option>
|
||||
<option value={3}>3회+</option>
|
||||
<option value={5}>5회+</option>
|
||||
</select>
|
||||
{(cuisineFilter || priceFilter || minMentions > 0) && (
|
||||
<button
|
||||
onClick={() => { setCuisineFilter(""); setPriceFilter(""); }}
|
||||
onClick={() => { setCuisineFilter(""); setPriceFilter(""); setMinMentions(0); }}
|
||||
className="p-1.5 -mr-1 text-gray-400 hover:text-brand-500 transition-colors touch-manipulation"
|
||||
title="음식 필터 초기화"
|
||||
>
|
||||
@@ -890,7 +907,7 @@ export default function Home() {
|
||||
)}
|
||||
</div>
|
||||
{/* 필터 전체 해제 */}
|
||||
{(channelFilter || cuisineFilter || priceFilter || countryFilter) && (
|
||||
{(channelFilter || cuisineFilter || priceFilter || countryFilter || minMentions > 0) && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setChannelFilter("");
|
||||
@@ -899,6 +916,7 @@ export default function Home() {
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
setMinMentions(0);
|
||||
setRegionFlyTo(null);
|
||||
}}
|
||||
className="flex items-center gap-1 rounded-lg px-2.5 py-1.5 bg-gray-50 dark:bg-gray-800/50 text-gray-500 dark:text-gray-400 hover:text-brand-500 transition-colors touch-manipulation"
|
||||
@@ -919,6 +937,7 @@ export default function Home() {
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
setMinMentions(0);
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => { setUserLoc({ lat: pos.coords.latitude, lng: pos.coords.longitude }); setRegionFlyTo({ lat: pos.coords.latitude, lng: pos.coords.longitude, zoom: 15 }); },
|
||||
@@ -1143,6 +1162,7 @@ export default function Home() {
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
setMinMentions(0);
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => { setUserLoc({ lat: pos.coords.latitude, lng: pos.coords.longitude }); setRegionFlyTo({ lat: pos.coords.latitude, lng: pos.coords.longitude, zoom: 15 }); },
|
||||
@@ -1255,6 +1275,7 @@ export default function Home() {
|
||||
setCountryFilter("");
|
||||
setCityFilter("");
|
||||
setDistrictFilter("");
|
||||
setMinMentions(0);
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => { setUserLoc({ lat: pos.coords.latitude, lng: pos.coords.longitude }); setRegionFlyTo({ lat: pos.coords.latitude, lng: pos.coords.longitude, zoom: 15 }); },
|
||||
|
||||
@@ -163,11 +163,12 @@ function MapContent({ restaurants, selected, onSelectRestaurant, flyTo, activeCh
|
||||
if (flyTo.zoom) map.setZoom(flyTo.zoom);
|
||||
}, [map, flyTo]);
|
||||
|
||||
// Pan and zoom to selected restaurant
|
||||
// Pan and zoom to selected restaurant — 현재 줌이 16 이상이면 유지(클러스터 expansion 후 재묶임 방지)
|
||||
useEffect(() => {
|
||||
if (!map || !selected) return;
|
||||
map.panTo({ lat: selected.latitude, lng: selected.longitude });
|
||||
map.setZoom(16);
|
||||
const currentZoom = map.getZoom() ?? 13;
|
||||
if (currentZoom < 16) map.setZoom(16);
|
||||
setInfoTarget(selected);
|
||||
}, [map, selected]);
|
||||
|
||||
|
||||
@@ -241,12 +241,15 @@ export default function NaverMapView({
|
||||
else m.panTo(latlng);
|
||||
}, [flyTo]);
|
||||
|
||||
// selected 변경 시 자동 중앙 + zoom
|
||||
// selected 변경 시 자동 중앙 — 현재 줌이 16 이상이면 그대로, 미만이면 16으로 확대
|
||||
// (클러스터 expansion으로 18까지 들어간 상태에서 마커 클릭 시 다시 16으로 줄어 클러스터링되는 것 방지)
|
||||
useEffect(() => {
|
||||
const m = mapRef.current;
|
||||
if (!m || !selected || !window.naver?.maps) return;
|
||||
if (selected.latitude == null || selected.longitude == null) return;
|
||||
m.morph(new window.naver.maps.LatLng(selected.latitude, selected.longitude), 16);
|
||||
const latlng = new window.naver.maps.LatLng(selected.latitude, selected.longitude);
|
||||
const targetZoom = Math.max(m.getZoom(), 16);
|
||||
m.morph(latlng, targetZoom);
|
||||
}, [selected]);
|
||||
|
||||
// 클러스터 계산 (bounds/zoom 변경 시)
|
||||
|
||||
@@ -7,6 +7,7 @@ import ReviewSection from "@/components/ReviewSection";
|
||||
import MemoSection from "@/components/MemoSection";
|
||||
import { RestaurantDetailSkeleton } from "@/components/Skeleton";
|
||||
import Icon from "@/components/Icon";
|
||||
import { formatRegion } from "@/lib/region";
|
||||
|
||||
interface RestaurantDetailProps {
|
||||
restaurant: Restaurant;
|
||||
@@ -127,9 +128,9 @@ export default function RestaurantDetail({
|
||||
<span className="text-gray-400 dark:text-gray-500">주소</span> <span className="text-gray-600 dark:text-gray-300">{restaurant.address}</span>
|
||||
</p>
|
||||
)}
|
||||
{restaurant.region && (
|
||||
{formatRegion(restaurant.region) && (
|
||||
<p>
|
||||
<span className="text-gray-400 dark:text-gray-500">지역</span> <span className="text-gray-600 dark:text-gray-300">{restaurant.region}</span>
|
||||
<span className="text-gray-400 dark:text-gray-500">지역</span> <span className="text-gray-600 dark:text-gray-300">{formatRegion(restaurant.region)}</span>
|
||||
</p>
|
||||
)}
|
||||
{restaurant.price_range && (
|
||||
@@ -180,26 +181,28 @@ export default function RestaurantDetail({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{restaurant.tabling_url && restaurant.tabling_url !== "NONE" && (
|
||||
{isKoreaRestaurant(restaurant) && restaurant.tabling_url && restaurant.tabling_url !== "NONE" && (
|
||||
<a
|
||||
href={restaurant.tabling_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="테이블링에서 줄서기 (새 탭)"
|
||||
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 bg-rose-500 hover:bg-rose-600 text-white rounded-lg text-sm font-semibold transition-colors"
|
||||
>
|
||||
<span>T</span>
|
||||
<span aria-hidden="true">T</span>
|
||||
<span>테이블링에서 줄서기</span>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{restaurant.catchtable_url && restaurant.catchtable_url !== "NONE" && (
|
||||
{isKoreaRestaurant(restaurant) && restaurant.catchtable_url && restaurant.catchtable_url !== "NONE" && (
|
||||
<a
|
||||
href={restaurant.catchtable_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="캐치테이블에서 예약하기 (새 탭)"
|
||||
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 bg-violet-500 hover:bg-violet-600 text-white rounded-lg text-sm font-semibold transition-colors"
|
||||
>
|
||||
<span>C</span>
|
||||
<span aria-hidden="true">C</span>
|
||||
<span>캐치테이블에서 예약하기</span>
|
||||
</a>
|
||||
)}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { Restaurant } from "@/lib/api";
|
||||
import { getCuisineIcon } from "@/lib/cuisine-icons";
|
||||
import Icon from "@/components/Icon";
|
||||
import { formatRegion } from "@/lib/region";
|
||||
import { RestaurantListSkeleton } from "@/components/Skeleton";
|
||||
|
||||
interface RestaurantListProps {
|
||||
@@ -50,8 +51,8 @@ export default function RestaurantList({
|
||||
<Icon name={getCuisineIcon(r.cuisine_type)} size={16} className="mr-0.5 text-brand-600" />
|
||||
{r.name}
|
||||
</h4>
|
||||
{r.region && (
|
||||
<span className="text-[11px] text-gray-400 dark:text-gray-500 truncate">{r.region}</span>
|
||||
{formatRegion(r.region) && (
|
||||
<span className="text-[11px] text-gray-400 dark:text-gray-500 truncate">{formatRegion(r.region)}</span>
|
||||
)}
|
||||
{r.rating && (
|
||||
<span className="text-xs text-yellow-600 dark:text-yellow-400 font-medium whitespace-nowrap shrink-0">★ {r.rating}</span>
|
||||
|
||||
@@ -51,6 +51,8 @@ export interface Restaurant {
|
||||
website: string | null;
|
||||
channels?: string[];
|
||||
foods_mentioned?: string[];
|
||||
// #533 — 의미있는(strong/unknown) 영상 언급 수
|
||||
video_count?: number | null;
|
||||
// #322 LLM 검증
|
||||
hidden?: boolean;
|
||||
hidden_reason?: string | null;
|
||||
@@ -168,6 +170,7 @@ export const api = {
|
||||
channel?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
min_mentions?: number;
|
||||
}) {
|
||||
const sp = new URLSearchParams();
|
||||
if (params?.cuisine) sp.set("cuisine", params.cuisine);
|
||||
@@ -175,6 +178,7 @@ export const api = {
|
||||
if (params?.channel) sp.set("channel", params.channel);
|
||||
if (params?.limit) sp.set("limit", String(params.limit));
|
||||
if (params?.offset) sp.set("offset", String(params.offset));
|
||||
if (params?.min_mentions) sp.set("min_mentions", String(params.min_mentions));
|
||||
const qs = sp.toString();
|
||||
return fetchApi<Restaurant[]>(`/api/restaurants${qs ? `?${qs}` : ""}`);
|
||||
},
|
||||
|
||||
23
frontend/src/lib/filters.ts
Normal file
23
frontend/src/lib/filters.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// 클라이언트 필터 순수 함수 — #533
|
||||
// page.tsx 의 filteredRestaurants 에서 사용하는 경계 로직을 테스트 가능하도록 분리.
|
||||
|
||||
/**
|
||||
* "의미있는 언급 수(video_count)" 기준으로 식당을 포함할지 판정한다.
|
||||
* 설계서: docs/design/533-min-mentions-filter/README.md
|
||||
*
|
||||
* - minMentions <= 0(기본값) → 필터 미적용, 항상 true.
|
||||
* - videoCount 가 null/undefined(미산정) → 0 으로 간주.
|
||||
* - videoCount >= minMentions 인 경우에만 true (경계값 포함).
|
||||
*
|
||||
* 예) passesMinMentions(1, 2) → false (1회는 2회 미만이라 제외)
|
||||
* passesMinMentions(2, 2) → true (경계값 포함)
|
||||
* passesMinMentions(null, 2) → false (미산정은 0 취급)
|
||||
* passesMinMentions(0, 0) → true (필터 미적용)
|
||||
*/
|
||||
export function passesMinMentions(
|
||||
videoCount: number | null | undefined,
|
||||
minMentions: number
|
||||
): boolean {
|
||||
if (minMentions <= 0) return true;
|
||||
return (videoCount ?? 0) >= minMentions;
|
||||
}
|
||||
22
frontend/src/lib/region.ts
Normal file
22
frontend/src/lib/region.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// 지역 표시 유틸 — #532
|
||||
// region 은 "나라|시도|구군" 파이프 구분 문자열. 사용자에게는 계층(breadcrumb)으로 보여준다.
|
||||
|
||||
/** 표시에서 제외할 더미/무의미 토큰. */
|
||||
const DUMMY_TOKENS = new Set(["", "null", "나라"]);
|
||||
|
||||
/**
|
||||
* 파이프 구분 region 을 "나라 › 시도 › 구군" 계층 문자열로 변환한다.
|
||||
* 빈 토큰·"null"·더미("나라")는 제거한다. 유효 토큰이 없으면 "".
|
||||
*
|
||||
* 예) "한국|서울|강남구" → "한국 › 서울 › 강남구"
|
||||
* "일본|null" → "일본"
|
||||
* "한국||관악구" → "한국 › 관악구"
|
||||
*/
|
||||
export function formatRegion(region: string | null | undefined): string {
|
||||
if (!region) return "";
|
||||
return region
|
||||
.split("|")
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => !DUMMY_TOKENS.has(t.toLowerCase()))
|
||||
.join(" › ");
|
||||
}
|
||||
Reference in New Issue
Block a user