공공데이터 기반 관광 앱 개발 시 데이터 저장 위치 선정 및 설계 방법 (공공누리 라이선스 주의점 포함)
공공데이터를 활용해서 관광 앱을 만들 때 가장 먼저 부딪히는 문제가 바로 "이 수많은 데이터를 어디에 두고 관리할 것인가"입니다. 모든 데이터를 서버 API로만 가져오자니 서버 비용이 걱정되고, 그렇다고 앱 안에 JSON 파일로 다 밀어 넣자니 나중에 데이터가 바뀌었을 때 대책이 안 섭니다.
저의 경우도 관광 데이터를 다루면서 처음에는 개발하기 편한 방식으로만 접근했다가, 나중에 운영 중에 데이터가 바뀌거나 라이선스 문제로 고생한 적이 있습니다. 이래저래 운영하면서 정립한 데이터 위치 선정 기준과 설계 방법을 자꾸 까먹어서 실무 메모용으로 정리해 둡니다.
운영하다 보면 꼭 터지는 데이터 구조 문제
처음에 구조를 잘못 잡고 배포하면 운영 단계에서 아래와 같은 골치 아픈 상황들을 마주하게 됩니다.
앱 업데이트 지연: 운영 시간 오타 하나 고치거나 폐업 확인되어 데이터 지우려는데, 데이터가 앱 내부 asset에 묶여 있어서 매번 마켓 앱 업데이트 심사를 받아야 합니다.
앱 용량 비대화: API 호출 비용 좀 아끼겠다고 관광지 수천 개의 이미지 URL과 정보를 전부 앱에 내장했다가 초기 다운로드 용량이 수백 MB로 커집니다.
이미지 엑박(Broken Link): 공공데이터 원본에서 이미지 URL 경로를 바꿨는데, 앱에 반영할 방법이 없어 사용자들이 엑박만 보게 됩니다.
라이선스 위반 위험: 공공데이터 출처표시나 이용 조건을 앱 안에서 제대로 안내하지 않았다가 법적 문제가 생길 수 있습니다.
불필요한 서버 비용: 굳이 서버가 없어도 되는 고정된 코드나 카테고리 데이터까지 매번 서버 API를 호출하게 만들어 서버 유지비만 늘어납니다.
보안 취약점: 급하게 개발하느라 앱 내부에 실제 공공데이터 API 키나 서버 관리자 경로를 하드코딩해서 노출하는 실수를 하기도 합니다.
데이터의 저장 위치는 개발이 편한 곳이 아니라 "얼마나 자주 바뀌는지, 용량이 얼마나 큰지, 오프라인 환경이 필요한지, 라이선스 조건이 무엇인지"를 기준으로 철저하게 나눠야 정신 건강에 좋습니다.
기본 개념: 데이터는 성격별로 쪼갭니다
관광 앱에 들어가는 데이터는 성격에 따라 아래처럼 분류해서 위치를 제각각 잡아야 합니다.
| 데이터 종류 | 예시 | 변경 빈도 | 추천 저장 위치 |
| 기본 장소 정보 | 이름, 주소, 좌표, 카테고리 등 | 낮음 | 앱 asset 또는 로컬 DB (SQLite/Room) |
| 운영 정보 | 운영 시간, 휴무일, 전화번호 등 | 중간 | 서버 API 또는 원격 설정 (Remote Config) |
| 행사/축제 정보 | 기간, 장소, 요금, 세부 일정 등 | 높음 | 서버 API |
| 이미지 리소스 | 썸네일, 상세 이미지 등 | 중간~높음 | CDN 또는 원격 이미지 서버 |
| 사용자 데이터 | 즐겨찾기(북마크), 최근 본 장소 등 | 사용자별 | 로컬 DB 또는 서버 동기화 |
| 공지/배너 | 이벤트, 긴급 점검 안내 등 | 높음 | 서버 API 또는 원격 설정 (Remote Config) |
선택 가능한 저장 방식별 장단점
모든 데이터를 하나의 방식으로 통일하는 것은 불가능합니다. 각 도구의 역할에 맞게 조합해야 합니다.
1. 앱 asset JSON
장점: 서버가 없어도 되고 네트워크 연결 없이 매우 빠르게 동작합니다.
단점: 앱을 새로 업데이트하기 전까지는 절대로 수정할 수 없습니다.
추천: 고정된 관광지 분류 카테고리, 변하지 않는 행정구역 목록 등에 적합합니다.
2. 로컬 내장 DB (SQLite / Room)
장점: 수천 개의 장소 데이터를 다룰 때 검색이나 필터링(거리순, 카테고리별) 속도가 빠릅니다. 오프라인에서도 돌아갑니다.
단점: 초기 배포 시 DB 파일을 생성하거나 앱 첫 실행 때 데이터를 적재하는 가공 작업이 필요합니다.
추천: 장소 수가 많고 현장에서 오프라인 검색을 지원해야 할 때 좋습니다.
3. 서버 API
장점: 원격 데이터베이스만 수정하면 실시간으로 모든 사용자에게 최신 데이터가 반영됩니다.
단점: 서버 구축 및 유지 비용이 들고, 서버가 터지면 앱의 해당 기능도 마비됩니다.
추천: 행사 일정, 실시간 운영 시간, 공지사항처럼 수시로 바뀌는 데이터에 필수적입니다.
4. CDN (콘텐츠 전송 네트워크)
장점: 대용량 관광지 이미지를 전 세계 사용자에게 빠르고 안정적으로 서빙합니다. 앱 용량을 줄이는 일등 공신입니다.
단점: 원본 이미지가 바뀌었을 때 캐시를 무효화(Invalidation)하는 전략을 세워야 합니다.
추천: 관광지 상세 이미지, 리뷰 사진 등 정적 리소스에 적합합니다.
5. 원격 설정 (Remote Config)
장점: 서버를 직접 구축하지 않고도 파이어베이스 등을 통해 간단한 텍스트나 기능 On/Off 값을 실시간으로 바꿀 수 있습니다.
단점: 구조가 복잡하거나 용량이 큰 데이터를 담기에는 적합하지 않습니다.
추천: 긴급 공지 팝업 노출 여부, 기능 점검 안내, 앱 버전 체크 등에 유용합니다.
실무에서 사용하는 하이브리드 설계 구조
저의 경우 기본 장소 정보(이름, 좌표 등)는 로컬 DB에서 빠르게 긁어오고, 변동성이 큰 운영 정보나 이미지 URL은 원격에서 받아와 보강하는 하이브리드 리포지토리 패턴을 주로 사용합니다. 이렇게 하면 산간 지역이나 네트워크가 잘 안 터지는 관광 현장에서도 앱의 기본 틀은 깨지지 않고 잘 돌아갑니다.
실제 프로젝트 구조를 단순화한 예시 코드는 아래와 같습니다. (서버 URL 및 API 키 등 보안 요소는 제외한 구조입니다.)
data class TourPlace(
val id: String,
val name: String,
val category: String,
val address: String,
val latitude: Double,
val longitude: Double,
val sourceName: String,
val sourceLicense: String,
)
data class TourPlaceRemoteInfo(
val placeId: String,
val openingHours: String?,
val notice: String?,
val imageUrl: String?,
val updatedAt: String,
)
class TourPlaceRepository(
private val localDataSource: TourPlaceLocalDataSource,
private val remoteDataSource: TourPlaceRemoteDataSource,
) {
suspend fun getPlace(placeId: String): TourPlaceDetail {
// 1. 변하지 않는 기본 정보는 로컬(DB/Asset)에서 먼저 가져옴 (네트워크 안 터져도 보장됨)
val baseInfo = localDataSource.findPlace(placeId)
?: throw IllegalArgumentException("장소 정보를 찾을 수 없습니다.")
// 2. 실시간 변동 데이터는 서버 API 호출 (실패 시 에러를 터뜨리지 않고 null 처리로 방어)
val remoteInfo = runCatching {
remoteDataSource.fetchPlaceInfo(placeId)
}.getOrNull()
// 3. 두 데이터를 결합하여 화면에 전달
return TourPlaceDetail(
id = baseInfo.id,
name = baseInfo.name,
category = baseInfo.category,
address = baseInfo.address,
latitude = baseInfo.latitude,
longitude = baseInfo.longitude,
openingHours = remoteInfo?.openingHours ?: "운영 정보 확인 필요",
notice = remoteInfo?.notice,
imageUrl = remoteInfo?.imageUrl,
sourceName = baseInfo.sourceName,
sourceLicense = baseInfo.sourceLicense,
updatedAt = remoteInfo?.updatedAt,
)
}
}
이렇게 설계하면 서버가 일시적인 장애를 일으키거나 와이파이가 끊겨도 사용자는 관광지 이름, 주소, 지도 좌표 등의 기본 정보는 여전히 볼 수 있어서 사용자 경험이 완전히 망가지는 것을 막을 수 있습니다.
대단히 중요한 공공데이터 이용 조건 (라이선스) 확인
많은 초보 개발자분들이 "공공데이터니까 아무렇게나 가져다 써도 되겠지"라고 생각했다가 큰코다치는 영역입니다. 특히 앱에 애드센스나 애드먼트, 애드몹 등을 달아서 광고 수익을 내거나 유료 기능을 넣을 계획이 있다면 "상업적 이용 가능 여부"를 무조건 눈에 불을 켜고 보셔야 합니다.
공공저작물 자유이용허락 표시제도인 공공누리(KOGL)의 유형을 반드시 체크하세요.
제1유형: 출처표시만 하면 상업적 이용 가능, 변경 및 재가공 가능 (가장 안전)
제2유형: 출처표시 필수, 상업적 이용 금지 (광고 붙은 앱/블로그 사용 불가)
제3유형: 출처표시 필수, 변경 금지 (내용 요약이나 가공 불가)
제4유형: 출처표시 필수, 상업적 이용 금지 + 변경 금지 (제한 사항 가장 많음)
단순한 위경도 좌표 데이터보다, 관광지 상세 설명문이나 사진 이미지 같은 '저작물' 성격이 강한 데이터일수록 라이선스 조건이 엄격하므로 아래 항목들을 꼼꼼히 검토해야 합니다.
| 확인 항목 | 검토 및 적용 기준 |
| 출처표시 | 앱의 상세 화면 하단이나 설정의 '오픈소스 및 출처' 페이지에 명확히 표기합니다. |
| 상업적 이용 | 수익형 앱(광고 포함)에서 사용 가능한 유형(제1유형, 제3유형)인지 확인합니다. |
| 변경 가능 여부 | 긴 설명을 요약하거나 다른 언어로 번역(재가공)해도 되는지 확인합니다. |
| 이미지 권리 | 공공데이터 포털에 올라온 이미지라도 원저작권자가 따로 있어서 배포를 금지하는 경우가 있으니 개별 확인이 필요합니다. |
| 데이터 최신성 | 원본 데이터가 언제 갱신되었는지 기준일을 받아와 화면에 함께 띄워주는 것이 좋습니다. |
현장 네트워크 환경을 고려한 오프라인/캐싱 전략
제주도 같은 관광지나 산간 지역을 다니다 보면 생각보다 LTE나 5G가 먹통이 되는 구간이 많습니다. 실시간 API에만 의존하는 앱은 현장에서 무용지물이 되기 십상입니다. 캐시는 단순히 속도를 높이는 목적뿐만 아니라 장애 대응 수단으로 바라봐야 합니다.
기본 장소 목록: 앱 내장 DB에 초기 탑재하거나, 첫 실행 때 전체 데이터를 한 번 다운로드 받아 로컬에 캐싱해 둡니다.
상세 설명 및 텍스트: 서버 API 조회를 우선하되, 실패 시 로컬 DB에 저장되어 있던 직전 데이터를 보여줍니다. 단, 오래된 데이터일 수 있으므로 화면에
updatedAt(갱신일)이나 "운영 정보 확인 필요" 같은 안내 문구를 띄워 오안내를 방지합니다.이미지 리소스: Glide나 Coil 같은 이미지 라이브러리의 디스크 캐시(Disk Cache) 기능을 적극 활용하고, 이미지 주소 세팅 시 CDN을 통해 트래픽을 분산시킵니다.
배포 전 필수 보안 및 운영 체크리스트
앱을 마켓에 올리기 전에 아래 체크리스트를 보면서 빠진 게 없는지 꼭 점검해 보세요.
[ ] 공공데이터 출처와 공공누리 라이선스 유형을 확인하고 앱 내에 명시했는가?
[ ] 상업적 이용 제한(제2유형, 제4유형)이 걸린 데이터를 광고가 붙은 앱에 쓰지 않았는가?
[ ] 코드나 빌드 결과물에 공공데이터 실제 API 인코딩/디코딩 키, 서버 URL, 관리자 경로가 하드코딩되어 노출되지 않았는가? (안전하게
local.properties나 서버 측에서 처리 추천)[ ] 이미지와 설명문 가공 시 별도의 저작권 위반 소지가 없는가?
[ ] 수시로 바뀌는 휴무일, 행사 기간 등의 데이터를 앱 내부 asset 파일에 고정하지 않았는가?
[ ] 서버 장애나 네트워크 오프라인 상태일 때 보여줄 기본 데이터와 에러 대응 문구(다이얼로그)를 구현했는가?
[ ] 사용자에게 혼선을 주지 않도록 데이터의 기준일 또는 최종 갱신일을 표시했는가?
요약 및 결론
결국 공공데이터 기반 앱 아키텍처의 핵심은 "데이터의 성격에 맞게 저장 위치를 쪼개고 밸런스를 잡는 것"입니다.
자주 바뀌지 않는 고정 데이터는 로컬 DB나 앱 내부에 두어 서버 비용을 아끼고 오프라인 안정성을 확보해야 합니다. 반면 수시로 변하는 정보나 대용량 리소스는 서버 API와 CDN을 통해 실시간성을 확보해야 운영이 피곤해지지 않습니다.
여기에 공공누리 라이선스 조건을 철저히 준수하는 것까지가 안정적인 관광 앱 서비스 운영의 기본입니다. 다음에 새 프로젝트 세팅할 때 이 기준으로 다시 뼈대를 잡아야겠습니다. 가물가물할 때마다 들어와서 보려고 남겨둡니다.
댓글
댓글 쓰기