MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
멀티플렉스엔 없는 영화, 어디서 하는지 몰랐다면. 독립·예술영화관 상영 시간표를 지도에서 바로 확인하세요.
Translation pending
MediaTypeScript · JavaScriptGitHub @JyngJOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
전국 각지에 흩어진 독립·예술영화관의 상영 정보를 한 곳에서 찾을 수 없다는 불편함에서 시작한 프로젝트입니다. 디자이너 1인이 기획·디자인을 담당하고, 개발자 1인이 합류해 프론트엔드·백엔드·데이터 파이프라인을 함께 구현했습니다. AI 코딩 도구(Claude Code)를 설계 단계부터 구현까지 실무 흐름에 통합해 소규모 팀의 개발 속도와 코드 품질을 함께 높이는 방식을 실험했습니다. 상영작 탭 (기본 진입 /) • 전국 독립·예술영화관 상영작을 리스트로 탐색 — 큐레이션 섹션·랭킹·지역(/films/area/[지역])·극장·감독 상세 페이지 • 검색엔진 대응: 지역·극장·감독·영화 상세가 서버 렌더링 + JSON-LD + sitemap·IndexNow 자동 통보Read the full README ↗
전국 각지에 흩어진 독립·예술영화관의 상영 정보를 한 곳에서 찾을 수 없다는 불편함에서 시작한 프로젝트입니다. 디자이너 1인이 기획·디자인을 담당하고, 개발자 1인이 합류해 프론트엔드·백엔드·데이터 파이프라인을 함께 구현했습니다. AI 코딩 도구(Claude Code)를 설계 단계부터 구현까지 실무 흐름에 통합해 소규모 팀의 개발 속도와 코드 품질을 함께 높이는 방식을 실험했습니다.
상영작 탭 (기본 진입 /)
/films/area/[지역])·극장·감독 상세 페이지지도 기반 탐색 (/map)
통합 검색
극장 바텀시트
데이터 파이프라인
docs/RUNBOOK-crawler.md 참조큐레이션
제보하기
| 영역 | 선택 | 이유 |
|---|---|---|
| 프레임워크 | Next.js 16 App Router | SSR + React Query 조합, 향후 서버 액션 확장 |
| 언어 | TypeScript (strict) | 타입이 문서 역할, 소규모 팀에서 인터페이스 계약 역할 |
| 서버 상태 | TanStack React Query v5 | 캐시·재검증 전략을 선언적으로 관리 |
| 스타일 | Tailwind CSS v4 + CSS Variables | 디자인 토큰 기반, 라이트 단일 테마 (다크 2026-08-04 폐지) |
| 지도 | Leaflet + react-leaflet v5 | 커스텀 DivIcon으로 포스터 핀 렌더링 |
| 베이스맵 | CARTO 래스터 타일 (voyager) | 국내 지도 3사는 자체 SDK만 허용해 Leaflet에 못 얹는다 |
| DB | Supabase PostgreSQL | RLS, 실시간, 인증을 한 곳에서 |
| 클라이언트 상태 | Zustand v5 | 테마, 지도 UI 상태 |
docs/DESIGN.md로 정리 — 색상·타이포그래피·간격 토큰, 라이트/다크 모드, 컴포넌트 계층 정의DESIGN.md + CLAUDE.md(아키텍처 규칙)를 기반으로 Claude Code와 페어 프로그래밍해 컴포넌트·화면 구성디자인 시스템은 /design-system에서 실제 화면으로 볼 수 있습니다. 파운데이션(색·타이포그래피·간격·radius·엘리베이션·아이콘·문구 규범), 프리미티브 컴포넌트 카탈로그, 그리고 코드 토큰과 피그마 변수를 이름으로 짝지어 값을 대조하는 코드 ↔ 피그마 차이 페이지로 구성됩니다. 값의 원본은 src/styles/tokens.css, 역할·규칙 설명은 docs/DESIGN.md이고, 이 사이트는 그 둘을 브라우저에서 확인하는 자리입니다. npm run ds:build가 만든 결과를 그대로 렌더합니다.
AI 에이전트용으로는 같은 내용을 텍스트로 내려주는 /design-system/llms.txt(전체는 llms-full.txt, 부분은 llms-tokens.txt·llms-components.txt·llms-writing.txt)가 있습니다.
/design-system은 내부 문서라robots.txt차단 + 페이지별noindex처리되어 검색에는 노출되지 않습니다.
Claude Code, OpenAI Codex, Cursor 세 가지 AI 코딩 도구를 용도에 따라 병행해 활용했습니다. Claude Code는 설계 파트너 역할로 — 복잡한 상태 설계(필터 흐름, 바텀시트 애니메이션), 크롤러 어댑터 아키텍처, 지도 핀 렌더링 최적화(icon 캐싱·뷰포트 컬링·줌 배칭), 스프링 애니메이션 물리 구현 등 트레이드오프가 있는 지점을 함께 검토하며 구현했고, Codex는 어드민 크롤링 파이프라인 초기 구현에, Cursor는 인라인 편집·빠른 수정에 활용했습니다. 전체 커밋의 약 2/3에 AI가 공동 기여자로 기록되어 있습니다.
mapSpring.ts)Leaflet의 내장 flyTo·flyToBounds를 RAF 루프 기반 스프링 물리로 전면 대체했습니다. v += (-k*(t-1) - d*v) * dt 공식으로 스칼라 t를 0→1로 구동하고, 위도·경도를 선형 보간합니다. 줌 변화가 있을 때는 zoomSnap을 일시 0으로 해제해 fractional zoom을 함께 보간함으로써, 기존 '줌 스냅 선행 → 팬' 방식의 순간 점프를 없앴습니다. springActive 플래그로 60fps setView 호출이 유발하는 React 상태 갱신 폭주를 차단하고, settledCallback으로 정착 즉시 클러스터 재계산을 트리거합니다.
지도 핀 내부에 영화 포스터를 직접 그리기 위해 Leaflet DivIcon + renderToStaticMarkup을 조합했습니다. 줌 레벨에 따라 포스터 수·크기가 동적으로 결정되고, 필터가 활성화된 경우 매칭되지 않는 영화는 반투명 처리 + "조건 외" 오버레이로 표시합니다. 같은 건물에 위치한 극장은 원형 배치로 핀이 겹치지 않도록 오프셋을 계산합니다.
영화·감독·극장·지하철역·지역명을 단일 쿼리로 처리하는 스코어링 엔진을 searchScoring.ts에 순수 함수로 구현했습니다. 초성 분리 매칭, 어두(語頭) 가중치, 한영 오타 보정, 타입 우선순위를 조합해 사용자 의도에 맞는 결과를 상위에 노출합니다. 감독 검색과 영화 검색이 교차 연결되어 — 감독을 검색하면 그 감독 작품 상영 극장이 함께 표시됩니다.
regions.ts에서 권역(서울·경기·인천 등)을 정의하고, GPS 좌표 또는 극장 주소로 매핑합니다. 사용자가 위치 권한을 허용하면 현재 좌표에서 가장 가까운 권역을 자동으로 선택하고, 해당 권역 경계(REGION_BOUNDS)를 기준으로 지도 뷰를 fit합니다.
줌·패닝 시 발생하는 렌더 횟수를 줄이기 위해 zoomRef + recomputeRef 패턴으로 줌 상태와 클러스터 계산을 한 React 렌더 사이클에 배칭합니다. 지하철 역 마커는 뷰포트 bounds 컬링으로 화면 밖 수백 개의 DOM 노드 생성을 방지하고, 역·핀 아이콘을 모듈 레벨 Map으로 캐싱해 줌 변경 시 재계산을 막습니다.
지도 필터(장르·국가)를 바텀시트가 열릴 때만 단방향으로 인계하고, 바텀시트에서 변경해도 지도에는 영향이 없습니다. "지도에서 필터 설정 → 바텀시트로 상세 확인 → 필터 조정" 흐름이 자연스럽게 이어지도록 설계했습니다.
극장마다 다른 웹사이트 구조를 CrawlerAdapter 인터페이스로 추상화했습니다. 새 극장을 추가할 때 어댑터 하나만 작성하면 파이프라인 전체에 연결됩니다. HTML 파서, Dtryx 예매 API, Moviee API 등 여러 방식을 동일한 인터페이스로 정규화합니다.
src/
├── app/ # Next.js App Router 페이지
│ ├── page.tsx # 홈 (지도 뷰)
│ ├── movie/[id]/ # 영화 상세
│ ├── director/[name]/ # 감독 필모그래피
│ ├── search/ # 영화·감독 검색 결과
│ ├── admin/ # 크롤링 후보 검수·어드민 콘솔
│ └── api/
│ ├── reports/ # 제보 접수 API
│ └── discord/ # Discord 봇 인터랙션 처리
│
├── components/
│ ├── primitives/ # 재사용 UI 원자 (Button, BottomSheet, Toast …)
│ ├── domain/ # 서비스 도메인 컴포넌트
│ │ ├── FilterBar # 날짜·장르·국가·예매 가능 필터 바
│ │ ├── TheaterSheet # 극장 바텀시트 (포스터·시간표·필터)
│ │ ├── DesktopDetailPanel # PC 슬라이드인 영화·감독 상세 패널
│ │ ├── MapPin # 포스터 핀
│ │ └── PosterThumb # 영화 포스터 썸네일
│ └── map/
│ ├── MapView.tsx # 전체화면 지도 + 검색 + 지하철 오버레이
│ ├── MapControls.tsx # ZoomSlider, ZoomTracker, ViewportTracker, FAB 등
│ └── PosterGrid.tsx # 바텀시트 포스터 그리드
│
├── lib/
│ ├── map/ # 지도 순수 함수
│ │ ├── posterLogic # 줌별 포스터 슬롯·크기 계산
│ │ ├── searchScoring # 통합 검색 스코어링 (초성·어두·한영 오타)
│ │ ├── searchUtils # 날짜 유틸·최근 검색
│ │ ├── distanceUtils # 거리 계산·포맷
│ │ └── subwayUtils # 지하철 역·노선 필터링
│ ├── mapSpring.ts # 스프링 물리 지도 이동 (RAF 루프, fractional zoom 보간)
│ ├── regions.ts # 권역 정의·GPS/주소 매핑
│ ├── genres.ts # 12개 표준 장르 정규화
│ ├── nations.ts # 국가 정규화
│ ├── catalog/ # 서버사이드 극장·영화·상영 데이터 집계
│ ├── reports/ # 제보 타입·저장·Discord 전송
│ ├── supabase/ # Supabase client + React Query hooks
│ ├── admin/ # 크롤러·KMDB·어드민 로직
│ ├── analytics/ # 이벤트 트래킹 클라이언트
│ └── adapters/ # 위치·스토리지 어댑터
│
├── hooks/ # 재사용 React 훅 (useIsDark, useIsDesktopLayout …)
│
└── types/ # 공유 TypeScript 타입
| Phase | 내용 | 상태 |
|---|---|---|
| 1 | 디자인 시스템, 토큰, 컴포넌트 | ✅ 완료 |
| 2 | 지도, 극장 탐색, 바텀시트, 지하철 오버레이 | ✅ 완료 |
| 3 | 영화·감독 검색, 상영시간표, 필터 시스템 | ✅ 완료 |
| 4 | 제보하기, Discord 운영 봇, 수도권 극장 확대 | ✅ 완료 |
| 5 | 지역 필터, 거리 표시, 감독 필터, 스프링 애니메이션 | ✅ 완료 |
| 6 | 큐레이션 섹션, Discord 컨펌 파이프라인 | ✅ 완료 |
| 7 | 계정 — 카카오·구글 로그인, 4탭 개편, 프로필 | ✅ 완료 |
| 8 | 관심 — 영화·감독·극장 등록, 지도 하이라이트, 관심 목록 | ✅ 완료 |
| 9 | 소식 — 관심 대상 새 상영 알림, 알림 설정 | ✅ 완료 |
| 10 | 네이티브 앱(Capacitor) 확장 | 예정 |
npm install
npm run dev # → http://localhost:3000
Node 18+,
.env.local환경 변수 필요 (Supabase URL·키, 지도 타일 키 등 — 전체 목록은docs/INFRA.md).
이 프로젝트는 Turbopack을 사용하지 않습니다 (--webpack강제).
지도 타일은 NEXT_PUBLIC_CARTO_API_KEY가 없으면 CARTO가 타일 이미지에 "API KEY REQUIRED"
워터마크를 구워서 내보냅니다. HTTP 200으로 응답하므로 요청 실패로는 잡히지 않습니다.
키는 무료이고 carto.com/basemaps/apikey에서 발급합니다.
분석 도구 설정과 이벤트/대시보드 정의는 docs/ANALYTICS.md에 정리되어 있습니다.
3일 이상 지난 상영시간표 자동 삭제 (PostgreSQL pg_cron)
show_date < CURRENT_DATE - INTERVAL '3 days'인 showtimes 레코드cleanup-old-showtimesDELETE FROM showtimes WHERE show_date < CURRENT_DATE - INTERVAL '3 days';지도 타일: © OpenStreetMap contributors, © CARTO
지하철 데이터: Kaggle Seoul Subway Geospatial Data (CC0 Public Domain)
실행 환경은 Node.js 22 이상입니다. 이메일 발송 작업도 같은 버전을 사용합니다.
선택형 이메일 등록 팝업과 월·금 오전 9시 요약 발송을 지원합니다. 기본값은 비활성이며, SQL 적용·Gmail 연결·환경 설정 후 활성화합니다. 이메일 알림 운영 안내와 구현 범위를 참고하세요.