CQ맵 개발노트: 중계기 PDF를 지도형 PWA로 바꾸기
KARL PDF를 106건의 지도 데이터로 가공하고 Kakao 지도, 거리 정렬, 설정 안내, 제보 흐름까지 묶은 CQ맵 MVP 개발 기록입니다.
CQ맵은 아마추어 무선 기사가 낯선 지역에서 UV 밴드 중계기를 빠르게 찾고, 초보자도 주파수·시프트·톤 설정을 따라 할 수 있게 돕는 Next.js PWA입니다. Hampass가 시험 학습을 돕는 앱이라면, CQ맵은 자격 취득 이후 실제 운용 단계에서 필요한 정보를 다루는 자매 앱에 가깝습니다.
이 노트는 README.md, docs/CQMAP_PRODUCT_ARCHITECTURE.md, docs/plans/PLAN_cqmap-phase1.md를 기준으로 MVP 구현 상태와 설계 의도를 정리한 기록입니다.
왜 CQ맵을 만들고 있는가
아마추어 무선 앱을 생각하면 시험 준비 앱과 실제 운용 보조 앱은 자연스럽게 이어집니다. Hampass가 자격 취득 전의 학습 문제를 다룬다면, CQ맵은 자격 취득 이후 "밖에서 실제로 어떻게 교신을 시작할 것인가"를 다룹니다.
중계기 정보는 공개 자료로 존재하지만, 이동 중 모바일에서 바로 쓰기에는 불편합니다. PDF를 열고, 지역을 찾고, 주파수와 시프트를 읽고, 내 위치와의 거리를 따져보는 과정이 현장에서는 꽤 번거롭습니다. CQ맵은 이 과정을 하나의 앱 흐름으로 줄이는 실험입니다.
제품 의도
CQ맵의 최종 목표는 단순히 "중계기가 어디 있는지"를 보여주는 것이 아닙니다. 실제로 사용자가 알고 싶은 질문은 조금 더 현실적입니다.
- 이 지역에서 지금 써볼 만한 중계기가 있는가?
- 주파수, 시프트, 톤을 어떻게 맞춰야 하는가?
- CQ를 했는데 응답이 없는 이유가 설정 문제인지, 무인 상태인지, 폐국인지 알 수 있는가?
- 운영자가 공식 상태나 점검 공지를 직접 알릴 수 있는가?
현재 MVP는 이 목표 중 첫 단계를 맡습니다. 읽기 전용 Static Repeater Finder로 시작해서, 지도·리스트·현재 위치 거리 정렬·상세 설정 안내·Telegram 제보·PWA 기반을 먼저 완성했습니다.
데이터 파이프라인
가장 까다로운 부분은 지도 UI가 아니라 데이터였습니다. 원본은 KARL의 중계기현황_26-02-23.pdf입니다. PDF 표에는 병합셀, 줄바꿈, 호출부호와 여러 주파수/망 정보가 섞여 있어 바로 앱 데이터로 쓰기 어렵습니다.
파이프라인은 다음 흐름으로 구성했습니다.
pdftotext -layout으로 PDF 텍스트 레이어를 추출합니다.- 원문 행을
raw-repeaters.json으로 보존합니다. - 주소와 주파수, 망구분을 정규화해
repeaters.draft.json을 만듭니다. - Kakao Local API로 지오코딩합니다.
- 좌표가 붙은 최종
repeaters.json을 생성합니다.
결과적으로 raw 원문은 199 rows, 지오코딩 전 draft는 106 rows, 앱에서 표시 가능한 최종 repeaters.json은 106건으로 정리되었습니다. 최종 데이터는 좌표 106/106, 지오코딩 실패 0건으로 검증되었습니다.
다만 이 숫자는 원래 계획의 "250+개소"와 다릅니다. 문서에서도 이 차이를 명시하고 있습니다. PDF의 실제 구조상 앱에서 사용자가 선택하는 단위는 "호출부호 하나"가 아니라 "운용 채널 하나"에 가깝습니다. 그래서 현재 MVP는 표시 가능한 운용 프로필 106건을 기준으로 잡는 것이 더 정확합니다.
지도와 위치 기반 탐색
지도는 Kakao Map SDK를 사용합니다. 한국 주소와 지오코딩 정확도를 고려하면 Kakao 의존은 MVP에서 합리적인 선택이었습니다. 대신 API 키와 도메인 허용 설정이 필요하다는 운영상의 의존성은 남습니다.
지도 구현에서 처리한 핵심은 다음과 같습니다.
- Kakao Map SDK 동적 로드
- 106개 중계기 마커 렌더링
- 상태/망구분에 따른 마커 스타일
- 리스트와 지도 전환
- 마커 클릭 시 선택 중계기 요약 표시
- 현재 위치 기반 거리 계산과 정렬
- 내 위치 마커
거리 계산은 Haversine 공식을 사용했고, 인제 좌표를 모의했을 때 6N0JD가 첫 항목으로 정렬되고 약 577 m로 표시되는 흐름을 확인했습니다.
상세 화면과 초보자 설정 안내
CQ맵에서 중요한 사용자 경험은 "지도에서 찾았다"가 아니라 "무전기를 어떻게 맞춰야 하는지 알았다"입니다. 그래서 Phase 6에서는 상세 라우트 106개를 SSG로 만들고, GetRadioSetupGuide use case와 설정법 카드 UI를 추가했습니다.
상세 화면에서는 다음 정보를 다룹니다.
- 호출부호
- 송수신 주파수
- 오프셋/시프트
- 톤 정보
- 상태 뱃지
- 위치와 거리
- 초보자용 단계별 설정 안내
단, 원본 PDF에는 CTCSS 톤 데이터가 없습니다. 그래서 tone은 number | null로 두었고, 톤이 없는 경우에는 "톤 미확인" 안내를 표시합니다. 이 부분은 Product Phase 2의 크라우드소싱 체크인과 정보 제보로 채워야 할 영역입니다.
제보와 PWA
MVP에서는 앱 내 로그인이나 체크인을 넣지 않았습니다. 대신 정보 오류를 Telegram으로 제보할 수 있게 했습니다. 이 흐름은 Hampass의 /contact와 Telegram Bot 패턴을 참고했습니다.
PWA와 검색 기반도 함께 추가했습니다.
public/manifest.json- service worker
- 글로벌 메타데이터와 OG
sitemap.tsrobots.ts- 상세 라우트 SSG
로컬 production QA에서는 Lighthouse 기준 Performance 96, Accessibility 100, Best Practices 100, SEO 100을 기록했습니다. 최신 Lighthouse CLI에서 별도 PWA 카테고리가 빠진 점 때문에 /manifest.json, /sw.js, /sitemap.xml, /robots.txt HTTP 200도 따로 확인했습니다.
현재 상태
문서 기준 CQ맵 MVP는 약 98% 완료 상태입니다.
- Phase 1 프로젝트 셋업과 도메인 모델: 완료
- Phase 2 PDF → JSON 데이터 파이프라인: 완료
- Phase 3 Repository와 리스트 화면: 완료
- Phase 4 Kakao 지도와 마커: 완료
- Phase 5 GPS와 거리 정렬: 완료
- Phase 6 상세, 설정법, 제보, PWA: 코드와 로컬 QA 완료
- 남은 일: Vercel 배포 인증, 환경변수 등록, 배포 도메인의 Kakao JavaScript 허용 도메인 설정, 실제 모바일 설치 확인
배포 전 필요한 환경변수는 KAKAO_REST_API_KEY, NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY, NEXT_PUBLIC_SITE_URL, 선택적으로 TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID입니다.
MVP에서 일부러 미룬 것
이번 MVP에서는 사용자 계정, 실시간 체크인, 운영자 관리 화면을 넣지 않았습니다. 기능으로는 매력적이지만, 데이터 신뢰도와 지도 탐색 경험이 검증되기 전에는 앱의 복잡도만 빠르게 올라갈 수 있기 때문입니다.
대신 정적 JSON과 SSG로 시작했습니다. 이 구조는 배포와 캐싱이 단순하고, 검색과 공유에 유리하며, 원본 PDF에서 추출한 데이터를 눈으로 검수하기에도 편합니다. 사용자가 실제로 "근처 중계기를 찾고 설정값을 확인하는 흐름"을 만족스럽게 쓴다는 증거가 생기면 그때 Supabase, 체크인, 운영자 상태 관리로 넘어가는 편이 더 안전합니다.
또 하나 미룬 것은 커뮤니티 기능입니다. CQ맵의 장기 설계에는 최근 사용 흔적, 관심 지역 알림, 운영자 공지, 무전기 모델별 설정 가이드가 들어갈 수 있습니다. 하지만 지금은 지도와 상세 정보의 기본 신뢰도가 먼저입니다.
다음 제품 단계
CQ맵의 장기 설계는 이미 CQMAP_PRODUCT_ARCHITECTURE.md에 분리되어 있습니다. MVP 이후의 핵심은 "정적 지도"에서 "실사용 상태를 함께 검증하는 앱"으로 넘어가는 것입니다.
Product Phase 2에서는 Supabase Auth와 PostgreSQL을 도입해 호출부호 기반 프로필, 중계기별 체크인, 최근 사용 흔적, 상태 신선도, n8n 알림을 붙일 계획입니다.
Product Phase 3에서는 운영자 소유권 신청과 운영자 공식 상태 관리가 들어갑니다. 운영자가 점검, 일시 중단, 폐국, 공지사항을 직접 관리하면 일반 사용자 제보보다 높은 신뢰도의 상태를 표시할 수 있습니다.
Product Phase 4 이후에는 무전기 모델별 설정 가이드, CHIRP/CSV 내보내기, 오프라인 저장, 즐겨찾기와 관심 지역 알림까지 확장할 수 있습니다.
개발하면서 얻은 판단
CQ맵은 지도 앱처럼 보이지만 실제 난이도는 데이터 모델과 신뢰도 설계에 있습니다. PDF에서 추출한 공식 데이터, 사용자의 현장 제보, 운영자의 공식 상태가 서로 다른 신뢰도를 갖기 때문입니다.
그래서 MVP에서는 백엔드를 서두르지 않고 정적 JSON과 PWA로 시작했습니다. 먼저 "쓸 수 있는 중계기 탐색" 경험을 만들고, 이후 사용자가 실제 운용 결과를 남길 수 있게 확장하는 순서가 이 앱에 더 맞습니다.
배포 후 확인할 질문
배포가 끝나면 단순히 "잘 열린다"보다 다음 질문을 먼저 확인하려고 합니다.
- 모바일에서 내 위치 권한 요청과 거리 정렬이 자연스러운가?
- 지도 마커가 많은 상태에서도 원하는 지역을 빠르게 훑을 수 있는가?
- 상세 페이지의 설정 안내가 초보자에게 충분히 구체적인가?
- 톤 미확인, 주소 불명확, 폐국 가능성 같은 불완전한 정보를 사용자가 오해하지 않는가?
- Telegram 제보가 실제 데이터 개선으로 이어질 만큼 부담이 낮은가?
이 질문에 대한 답이 모이면 CQ맵의 다음 기능 우선순위도 더 선명해질 것입니다. 지도 앱은 기능 수보다 현장에서의 신뢰가 중요하기 때문에, 초기에는 작은 피드백을 빠르게 반영하는 쪽으로 운영하려고 합니다.
현재의 CQ맵 개발노트는 완성 발표라기보다 배포 직전 MVP 검증 기록입니다. 다음 기록은 Vercel 배포, Kakao 도메인 설정, 실제 모바일 설치 QA, 그리고 첫 사용자 피드백 정리로 이어질 예정입니다.