WallpaperMachine
The wallpapers you love. A new home on your Mac.
명정 캠퍼스 사람들이 함께 채우는 점심·카페 지도
Translation pending
LifestyleTypeScript · CSSGitHub @myeongjeong-lunch-mapOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
명정 캠퍼스 사람들이 함께 채우는 점심·카페 지도 (Next.js · 네이버 지도 · Supabase)
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗명정 캠퍼스(서울 서초구 반포대로 45 명정빌딩) 사람들이 함께 채우는 점심·카페 지도. 노션 표로 관리하던 「명정 캠퍼스 점심 지도」를 네이버 지도 위로 옮겼다.
https://myeongjeong-lunch-map.vercel.app
로그인 없이 링크만 있으면 누구나 보고, 가게와 꿀팁을 더할 수 있다. 구글로 로그인하면 내 기록이 기기를 바꿔도 이어진다. 용어는 GLOSSARY.md를 따른다.
| 탭 | 하는 일 |
|---|---|
| 🏆 랭킹 | 이번 주(최근 7일 좋아요 × 2 + 꿀팁) / 전체(좋아요 − 싫어요). 이번 주 기록이 없으면 전체를 보여 준다 |
| 📍 목록 | 카테고리(여러 개 중 하나라도), 키워드(모두 가진 가게), 최대 도보 시간, 이름으로 거른다 |
| 💡 꿀팁 | 모든 가게의 최근 꿀팁 피드. 누르면 그 가게로 간다 |
| 🎟️ 추첨 | 팀 추첨 (아래) |
| 🚶 산책 | 산책 장소·추천 코스·내 코스·점심 코스 (아래) |
/?team=…)로 바로 들어올 수 있다. 팀을 만든 사람이 조장/admin)ADMIN_SECRET으로 로그인해 가게 이름·카테고리·네이버 링크를 고치거나 가게·꿀팁을 지운다/lunch로 옆 패널에 오늘 점심 추천과 이번 주 랭킹 → Claude Code에 "오늘 점심" 패널 붙이기| 문서 | 내용 |
|---|---|
| GLOSSARY.md | 용어 (가게, 꿀팁, 키워드, 평가, 랭킹, 도보 시간 …). 코드와 화면 문구는 이 용어를 따른다 |
| docs/adr/ | 되돌리기 어렵거나 이유가 안 보이는 결정 (도보 시간 매일 재계산, 메뉴판을 네이버 페이지로 띄우는 이유, 산책 코스 시간은 구간을 더해서 구함, 점심 코스의 가게 구간은 범위로 거르고 남은 쌍만 계산) |
| AGENTS.md | Next.js 16을 쓰므로 코드를 쓰기 전에 node_modules/next/dist/docs/를 확인할 것 |
src/
app/
page.tsx 지도 화면 (LunchMap)
admin/ 관리자 화면 (ADMIN_SECRET 로그인)
auth/ 구글 로그인 login·callback(기록 옮기기)·logout
api/
places/ 가게 목록·추가, [id]/tips·vote·keywords·favorite
me/ 내 계정(로그인 여부·닉네임), me/tips(내 꿀팁)
teams/ 팀 목록·만들기, [id]/members·box(추첨통)·box/entries·box/draw(다시 뽑기 포함)·box/decide
tips/ 꿀팁 피드
search/, reverse/ 네이버 장소 검색, 좌표 → 주소
walk/ 산책 장소·코스·구간·가게 구간, path·lunch-path(구간별 보행 경로)
cron/walking/ 매일 도보 시간 재계산 (Vercel Cron)
cron/walk-legs/ 매일 산책 구간·가게 구간 재계산 (Vercel Cron)
cron/purge-write-events/ 매일 30일 지난 남용 방지 기록(IP 해시) 삭제 (Vercel Cron)
street/ 길거리 제보: 목록·제보, [id]/check(노점 확인), [id](고정 노점으로)
mcp/ MCP 서버 (읽기 전용 도구 7개)
admin/ 관리자 수정·삭제
components/ LunchMap(전체 틀) + map/ place/ draw/ walk/ street/ me/ admin/ ui/ (기능별 폴더)
lib/
domain.ts 용어·타입·키워드 목록·랭킹 계산
server/ Supabase, 네이버, TMAP, 쓰기 방어(허니팟·속도 제한), 쿠키·로그인 세션
supabase/migrations/ DB 스키마 (순서대로 적용)
scripts/ 노션 데이터 옮기기, 플레이스 ID 채우기, Vercel 환경 변수 올리기
claude-mod/lunch-today/ Claude Code "오늘 점심" 패널 mod (.claude-plugin/marketplace.json이 설치 목록)
icn1)lm_voter)다. 로그인하면 그 브라우저의 기록을 계정으로 옮긴다 (ADR 0008).npm install
cp .env.example .env.local # 값 채우기 (아래 참고)
npm run dev # http://localhost:3000
.env.local의 키는 공유하지 않는다. 둘 중 하나를 고른다.
npx vercel link → npx vercel env pull .env.local.
운영 DB를 그대로 쓰니 시험 데이터는 꼭 지운다..env.example의 주석대로 각 서비스에서 무료로 발급받고, 새 Supabase 프로젝트에 supabase/migrations/를 순서대로 실행한다.
네이버 지도 허용 URL에 http://localhost:3000을 넣어야 지도가 뜬다.구글 로그인은 Supabase Auth를 쓴다. 새 환경 변수는 없고, Supabase 프로젝트마다(개발·운영 각각) 대시보드에서 한 번 설정한다.
https://<프로젝트 ref>.supabase.co/auth/v1/callback. OAuth 동의 화면의 범위는 기본(이메일·프로필·openid)만 둔다.localhost로 두지 않는다.http://localhost:3000/**와 배포 주소 + /** (예: https://myeongjeong-lunch-map-dev.vercel.app/**). 로그인은 /auth/callback?next=…처럼 뒤에 값을 붙여 돌아오므로 /auth/callback만 넣으면 맞지 않는다.설정하지 않으면 로그인 버튼만 실패하고(👤 화면에 "로그인하지 못했어요"), 나머지 기능은 그대로 동작한다.
방문자 수·페이지 조회 수는 Vercel Web Analytics로 본다. 코드(src/app/layout.tsx의 <Analytics />)는 들어 있고, Vercel 프로젝트마다(dev·운영 각각) 대시보드 → Analytics → Enable을 한 번 눌러야 모이기 시작한다. 쿠키를 쓰지 않으며, 모으는 항목은 개인정보처리방침(/privacy)에 적혀 있다.
점심 지도는 MCP 서버(/api/mcp, Streamable HTTP, 읽기 전용, 인증 없음)를 연다. 연결하면 Claude에게 "10분 안에 갈 수 있는 국밥집 추천해 줘", "부캉팀 추첨통에 뭐 들어 있어?"처럼 물어볼 수 있다.
| 서버 | 주소 |
|---|---|
| 운영 | https://myeongjeong-lunch-map.vercel.app/api/mcp |
| dev | https://myeongjeong-lunch-map-dev.vercel.app/api/mcp |
Claude Code — 터미널에서 한 줄. --scope user를 붙이면 모든 프로젝트에서 쓴다.
claude mcp add --scope user --transport http lunch-map https://myeongjeong-lunch-map.vercel.app/api/mcp
claude mcp list에 lunch-map … ✔ Connected가 보이면 된다. 연결은 새로 여는 세션부터 쓸 수 있다.
Claude 앱 · claude.ai — 설정 → 커넥터 → 사용자 지정 커넥터 추가 → 이름 점심 지도, URL에 운영 주소. 대화에서 커넥터를 켜고 물어본다. (사용자 지정 커넥터는 Pro·Max·Team·Enterprise 요금제에서 된다)
다른 MCP 클라이언트 — Streamable HTTP를 지원하면 위 주소를 그대로 넣는다. stdio만 되면 npx -y mcp-remote <주소>로 감싼다.
| 도구 | 하는 일 |
|---|---|
search_places | 이름·카테고리·키워드·최대 도보 분으로 가게 찾기 |
get_place | 가게 하나의 주소·도보 시간·평가·키워드·최근 꿀팁·네이버 지도 링크 |
get_ranking | 랭킹 (이번 주 / 전체). 가 볼 곳은 빠진다 |
pick_lunch | 오늘 뭐 먹지: 조건 안에서 무작위 한 곳 (가 볼 곳은 빼고) |
get_team_box | 팀의 열린 추첨통: 가게·넣은 횟수·확률·넣은 사람 |
list_walk_courses | 추천 산책 코스와 코스 시간 |
list_street_stalls | 지금 보이는 길거리 노점 (종류로 거르기) |
도구는 src/lib/server/mcpTools.ts에 있다. 쓰기 도구(꿀팁·평가·추첨통 넣기)는 아직 없다.
claude-mod/lunch-today는 Claude Code 옆 패널에 🍱 오늘 점심을 띄우는 mod(플러그인)다. 위 MCP 서버에서 추천 한 곳과 이번 주 랭킹 3곳을 받아 보여 준다.
설치 — Claude Code 터미널 세션의 입력창에서:
/plugin install lunch-today --marketplace myeongjeong-lunch-map/lunch-map
Add marketplace?에 y, 범위는 user(Enter)를 고르면 Installed lunch-today가 뜨고 바로 켜진다.
셸에서 한 줄로:
claude plugin install lunch-today --marketplace myeongjeong-lunch-map/lunch-map
데스크톱 앱(/plugin이 안 되는 곳): 입력창 옆 + → Plugins → Add marketplace에 myeongjeong-lunch-map/lunch-map → Add plugin에서 lunch-today.
쓰기
/lunch — 패널을 열고 추천 한 곳 + 이번 주 랭킹을 보여 준다/lunch 한식 10분, /lunch 분식, /lunch 국밥 — 카테고리, 최대 도보 분, 이름 일부로 조건을 건다r), 조건 지우기(c)참고
lunch-map MCP가 연결돼 있으면 그것으로 부르고, 없거나 막히면 같은 주소에 HTTP로 직접 요청한다. 그래서 MCP를 따로 연결하지 않아도 동작한다claude --plugin-dir claude-mod/lunch-today로 띄우면 저장할 때마다 다시 불러온다. 고친 뒤 claude plugin validate claude-mod/lunch-today로 확인한다claude plugin update lunch-today 뒤 /reload-pluginsdev에서 이슈 번호를 넣어 브랜치를 딴다 (feat/12-team-ranking, fix/…).npm run typecheck
npm run lint
npm run build
dev로 PR을 올린다. 본문은 PR 템플릿의 다섯 칸(배경·의도·구현·중점 리뷰 항목·테스트)을 채우고 첫 줄에 Closes #이슈번호를 쓴다. Claude로 작업하면 CLAUDE.md가 이 흐름을 따르게 한다. 용어가 새로 생기거나 바뀌면 GLOSSARY.md도 같이 고친다.supabase/migrations/에 다음 번호로 SQL 파일을 추가한다. 이미 적용된 파일은 고치지 않는다.dev에 머지되면 deploy-dev.yml이 Vercel dev 프로젝트(myeongjeong-lunch-map-dev, 개발용 키·개발 DB)에 배포한다. dev 서버에서 확인한 뒤 dev → master PR로 운영에 낸다.
master에 머지되면 GitHub Actions(.github/workflows/deploy.yml)가 타입 검사·린트 후 Vercel 운영 환경에 자동 배포한다.
DB를 바꾸는 PR은 개발 DB에 먼저 적용하고, 운영 DB에는 master에 머지하기 전에 적용한다.
Vercel Hobby 플랜은 프로젝트 주인이 아닌 사람의 커밋을 Git 연동으로 배포하지 못해서, 주인 계정 토큰(VERCEL_TOKEN Secret)으로 CLI 배포를 한다.
저장소의 .mcp.json에 개발용 MCP 두 개가 들어 있다. Claude Code로 이 폴더를 열면 쓸지 묻는다. 키는 파일에 없고, 처음 한 번 /mcp에서 서버를 골라 Authenticate로 내 계정에 로그인한다.
| 이름 | 하는 일 | 범위 |
|---|---|---|
supabase-dev | 개발 DB 테이블·데이터 조회, 마이그레이션 확인 | 개발 DB(lunch-map-dev)만, 읽기 전용 |
vercel | 배포 상태·로그 확인, 문서 검색 | 로그인한 Vercel 계정의 권한 그대로 |
supabase-dev는 개발 DB 프로젝트가 있는 Supabase 조직의 멤버여야 보인다.vercel은 Vercel 프로젝트에 접근 권한이 있는 계정이어야 배포 정보가 보인다 (Hobby 플랜은 팀원을 초대할 수 없어 지금은 프로젝트 주인만).내 컴퓨터를 켜 두지 않아도 claude.ai/code나 모바일 앱에서 이 저장소로 작업을 맡길 수 있다. 저장소에는 이미 준비가 되어 있고, 사람마다 클라우드 환경을 한 번 만들면 된다.
저장소에 들어 있는 것
CLAUDE_CODE_REMOTE=true)에서만 npm ci를 하고, package-lock.json이 그대로면 건너뛴다. 로컬에서는 아무것도 하지 않는다.CLAUDE.md, AGENTS.md, .mcp.json, 저장소 안의 .claude/ 설정은 클라우드에서도 그대로 읽힌다. 내 컴퓨터의 ~/.claude(개인 스킬·플러그인·메모리)는 따라가지 않는다.클라우드 환경 만들기 (claude.ai/code → 환경 선택 → 새 환경)
명정 점심 지도.env.dev.shared의 개발용 값을 그대로 붙여 넣는다 (.env 형식). 운영 키(.env.prod.shared, .env.local)는 넣지 않는다. 클라우드 세션은 개발 DB만 만진다.*.supabase.co
*.apigw.ntruss.com
apis.openapi.sk.com
map.naver.com
m.place.naver.com
oapi.map.naver.com
클라우드에서 다를 점
gh pr · gh issue가 403이다. PR은 세션 화면의 Create PR 버튼으로 만들고, 이슈·담당자 지정은 gh api(REST)로 한다. 예: gh api repos/myeongjeong-lunch-map/lunch-map/issues -f title=... -f body=... -f "assignees[]=bbangHo"dev에서 브랜치 → dev로 PR)은 로컬과 같다. dev·master에 직접 push하지 않는다.SemVer v주.부.수를 쓴다. 운영 반영(dev → master 머지) 한 번이 버전 하나다.
master에 머지되면 release.yml이 지난 태그 이후 들어온 PR 브랜치 이름을 보고 다음 버전을 정해 태그와 GitHub Release를 만든다
feat/… PR이 하나라도 있으면 부 (v1.1.0 → v1.2.0)fix/… 등 그 밖의 PR만 있으면 수 (v1.1.0 → v1.1.1)dev → master 릴리스 PR에 release:major 라벨을 붙였을 때만 (v1.1.0 → v2.0.0)package.json의 version은 쓰지 않는다. 버전의 기준은 태그다master — 운영 서비스 코드. 머지하면 https://myeongjeong-lunch-map.vercel.app 에 배포된다dev — 개발 서버 코드. 머지하면 https://myeongjeong-lunch-map-dev.vercel.app 에 배포된다. dev와 master 모두 PR로만 바꾼다prototype/ui-variants — 화면 시안 A~E(버려도 되는 시안 코드). 시안 E로 결정했고 기록용으로만 둔다