- 시도 코드로 요청한
GET /v1/forecasts/visitors가 항상 unavailable이던 것을 고쳤다. KTO 공식 집중률은 시군구 단위로만 수집되므로 시도 게시본에 소속 시군구 전체 관광지의 날짜별 평균을 합성 기본 행으로 넣고,sample_count와basis("시도 내 시군구 N곳, 관광지 M곳의 공식 집중률 평균")로 근거를 밝힌다. 시군구 행은 시군구 게시본이 참조하므로 시도 게시본의normalized_references는 시도 자체 행만 담는다. 품질 플래그aggregated_from_sigungu와 메타데이터aggregated_sigungu_count를 추가했다. - 스키마와 문서에만 있고 항상 null이던
requested_area_code(지역 인사이트, 방문 시계열, 방문 전망)와data_area_code,spatial_resolution(방문 전망)을 채운다.requested_area_code는 클라이언트가 보낸 식별자를 그대로 돌려주고, 나머지는 게시본 지역의 코드와 공간 단위다. 조회 키는 바뀌지 않는다. GET /v1/places를 추가했다. 시도 또는 시군구의 canonical 관광지를 제목 순으로 반환하며, 시도 요청은 소속 시군구의 관광지를 포함한다.lang으로 제목 언어를 고르되 없으면 한국어로 대체하고 항목마다 실제language를 표시한다.q는 제목 부분 일치,limit(1100, 기본 20)과10,000)으로offset(0total안에서 페이지를 이동한다. 병합된 별칭 관광지와 한국어 제목이 없는 관광지는 목록에 없다. 공개 API는 8개가 된다.
- 사용자 승인으로
POST /v1/recommendations/destinations와 대시보드 추천 화면을 삭제했다. 공개 API는 7개이며 삭제된 경로는 404를 반환한다. - 추천 전용 스냅샷 생성과 스케줄러 등록을 제거했다. 장소 상세 조회와 원천 수집은 유지한다.
- 고정 국가 통계 seed와 임의 점수 및 과거 실적 기반 전망 대체를 제거했다. 수집 근거가 없으면 null 또는 unavailable로 응답한다. DB 정리 마이그레이션
20260917_0011은 별도 적용이 필요하다.
운영 배포 release 20260917T014213Z. 이 판의 목표는 공개 API 8개가 설계한 데이터를 실제로 수집·조합해 내도록 만드는 것이다. 엔드포인트별 현황은 저장소 루트 README의 "API 제공 범위"에 있다.
-
NAVER 검색 트렌드(SRC_NAVER_TREND)를 켰다. NAVER는 한국어 검색만 답하므로 시장별 외국어 키워드 대신 지역 여행 키워드 18개("한국 여행", "서울 여행", …)를 하루 5개씩 순환 수집하고, 국내 검색 관심은 특정 방한시장에 속하지 않으므로 country 없이 저장한다. 트렌드 응답은 social_sources를 지정하지 않은 요청에서 한국어 키워드의
search_ratio를 NAVER로 채운다. 운영 반영에는NAVER_STORAGE_POLICY_APPROVED=true설정이 필요하다. -
방한시장의
passengers를 채운다. 인천공항 국가별 항공통계 서비스의 여객 오퍼레이션(getTotalNumberOfPassenger)을 운항편 오퍼레이션과 함께 수집하고, 같은 국가·월의 관측에 운항편 수와 여객 수를 합쳐 저장한다. 여객 통계를 수집하기 전 달은 null로 남는다. -
시군구 방문 전망이 공식 예측 없이 unavailable로 나오던 것을 고쳤다. KTO 공식 예측은 관광지 단위이므로 지역 요청은 그 지역 관광지들의 공식 집중률 평균을
official로 내고,sample_count에 평균에 쓴 관광지 수와basis에 근거를 표시한다. 관광지명을 지정한 요청과 시도 참고 전망은 그대로다. -
트렌드가 YouTube 고정 키워드 15개 외에는 항상 unavailable이던 것을 보완했다. 이미 수집 중인 KTO 관광자원 수요 지수(관광지명·지역별 월간, 0~100)를 관측이 있을 때 응답에 포함해 한국어 관광지명 키워드와
area_code필터가 동작한다.area_code가 있으면 meta.sources에도 이 원천을 표시한다. -
KTO 중심 관광지·연관 관광지가 TourAPI 관광지에 붙지 않아 관광지 상세의
hub,related_places와 추천의related_places가 항상 비어 있던 문제를 고쳤다. 두 KTO 원천은 TATS 코드로, 상세 API는 TourAPI content id로 관광지를 식별하는데, 같은 시도 안에서 정규화한 한국어 이름이 유일하게 일치하고 좌표가 있으면 1km 안에서 일치할 때만 같은 관광지로 본다(좌표만으로는 합치지 않는다). 새로 수집되는 허브·연관 행은 TourAPI 관광지에 바로 붙고, 이미 만들어진 TATS 관광지 행은 스케줄러 잡(eden:place:crosswalk, 6시간마다 최대 3,000건)이 canonical로 이어 붙이며 읽기 경로는 이어 붙인 행의 관계를 함께 조회한다. -
2026-09-11에 껐던 관광지 원천 5개(TourAPI 영어·일본어·중국어 간체, KTO 중심 관광지, KTO 연관 관광지)를 다시 켰다. 언어별 카탈로그는 한국어 카탈로그로 고른 essential 관광지의 번역만 붙이고 새 관광지를 만들지 않는다(시도 3개씩 순환, 새 관광지 한도 0). 레지스트리의 enabled는 코드의 원천 범위를 따르며 스케줄러가 시작할 때 맞춘다.
-
관광지 상세의
overview가 항상 null이던 문제를 고쳤다. TourAPI 목록(areaBasedList2)에는 소개문이 없으므로, essential 관광지 중 소개문이 없는 곳이 있으면 TourAPI 실행이 시도 목록 대신 상세(detailCommon2)를 한 실행에 60곳씩 수집해 한국어 소개문을 채운다. 원천에 소개문이 없는 관광지는 빈 값으로 표시해 다시 요청하지 않으며 API에서는 null로 낸다. 목록 갱신이 저장된 소개문을 지우지 않는다. -
원천이 없어 영구 null인 필드(지역 인사이트의 avg_stay_nights·age_index, 방한시장의 passengers, 추천의 estimated_budget_krw) 때문에 세 엔드포인트가 항상 partial이던 판정을 바꿨다. 이 필드들은 "미제공"으로 문서화하고 가용성 판정에서 제외하며, 응답 구조와 값(null)은 그대로다. 미제공 필드 목록은 README의 "Fields That Are Not Provided"에 있다.
-
주변 상권 수집이 6시간마다 관광지 5곳만 돌아 essential 관광지 480곳 중 298곳에 1km 안 상권 행이 없고 한 바퀴에 약 24일이 걸리던 것을, 한 실행에 20곳(응답 약 25KB씩, 런당 요청 예산 22)으로 늘려 일주일 안에 채우도록 했다. 주기와 반경, 저장 방식은 그대로다.
-
시군구 방문 전망의
holiday가 항상 null이던 문제를 고쳤다. 공휴일 행은 시도에만 기록되므로 시군구 게시본이 날씨와 같은 방식으로 부모 시도의 공휴일 행을 상속한다. -
방문 전망이 축제나 공휴일이 없는 날을 "참고 원천 없음"으로 세어 응답이 거의 항상 partial이던 문제를 고쳤다. 축제·공휴일 원천은 행사가 있는 날에만 행을 쓰므로, 게시본에 두 원천의 최근 성공 실행이 덮는 날짜 범위(
reference_coverage)를 기록하고 그 범위 안에서 행이 없는 날은 빈 목록과false로 낸다. 범위 밖이나 원천이 오래됐으면 이전처럼 null과 partial이다. -
재외공관 공지(SRC_EMBASSY_NOTICE)가 외교부 사이트 앞의 대기열 페이지(
/waitingroom/)를 목록으로 받아 5개 공관 모두ValueError로 실패하던 문제를 고쳤다. 수집기가 같은 클라이언트로 대기열 상태를 폴링해 통과한 뒤 원래 페이지를 다시 요청하며, 폴링은 실행 시간 예산 안에서만 한다. 공관 공지 요청 예산을 20에서 40으로 올려 대기열 통과 비용을 흡수한다. -
기상청 단기예보(SRC_KMA_FORECAST)와 TourAPI 목록(SRC_TOUR_KO)의 런당 요청 예산이 배치 크기와 같아 일시 오류 한 번에 마지막 지역이 예산 초과로 실패하던 문제를 고쳤다. 두 원천은 배치에 재시도 여유 2회를 더한 예산을 받는다. TourAPI 시도 목록은 한 번에 3개만 수집해 2 MiB 바이트 예산 안에 들어가게 했다(전체 순환은 6회).
-
소상공인 상권(SRC_SEMAS_SHOPS) 수집 계획에 응답 헤더의 기준년월(
stdrYm) 워터마크를 추가했다. 이전에는 발표시각을 몰라 매 실행이 degraded로 분류되고, 같은 관광지를 다시 방문해 저장할 새 행이 없으면 실행이 failed로 기록돼 재수집 간격이 최대 96시간까지 늘어났다. -
기준정보 재시드가 레지스트리 evidence를 통째로 덮어써 스케줄러의 순환 커서(
collection_cursor)가 0으로 돌아가던 문제를 고쳤다. 커서는 재시드 후에도 유지된다. -
공식 공지 응답의 신선도 한도가 3시간으로 고정돼 12시간 수집 주기 사이에 항상 stale로 표시되던 문제를 고쳤다. 한도는 요청 범위 원천의 refresh policy를 따른다.
-
추천 항목의
sources에 계절 혼잡도 근거 원천(SRC_KTO_REGIONAL_VISITORS)이 빠져 있던 것을 보완했다. -
알려진 제한과 보류한 작업은 KNOWN_GAPS.md에 정리했다.
-
관측 보존 검사가 시간 예산에 걸려 중간에 멈출 때 스트리밍 커서를 닫지 않아 풀에 반환된 연결이
Commands out of sync로 깨지고 정리 실행의 약 40%가 실패하던 문제를 고쳤다. 보존 정책과 삭제 배치 크기는 그대로다. -
스케줄러 서비스 유닛에
MALLOC_ARENA_MAX=2를 두어 5분마다 도는 정리 작업의 스레드 힙 파편화로 RSS가 시간당 약 90MB씩 커지던 현상을 억제한다. -
수집 스케줄러를 API 프로세스에서 분리해
python -m app.scheduler로 단독 실행할 수 있게 했다. 잡, 주기, 리더 락, 용량 게이트는 그대로이며 리더 락을 잃으면 프로세스가 종료되어 systemd가 다시 시작한다. 선택한 loopback 포트로 스케줄러 지표를 노출한다. -
production API는 스케줄러를 끄고 실행해도 파일럿 사용량 기록용 ingestion 연결을 유지한다. 개발과 테스트 환경은 이전처럼 쓰기 연결을 열지 않는다.
-
soak 증거는
eden-scheduler서비스의 상태, 재시작 횟수, 메모리를 함께 기록하고, 스케줄러 활성 여부를 API readiness와 서비스 상태에서 함께 판정한다. 정지된 스케줄러 서비스는 서비스 장애가 아니라 scheduler-off 구간으로 본다. -
운영 systemd 유닛과 watchdog을
api/deploy/에 둔다.eden-scheduler.service는PartOf와Wants로eden-api.service에 묶여 배포 스크립트 변경 없이 API와 함께 정지·재시작된다. 스케줄러만 죽으면 스케줄러만 재시작된다. -
분리 후 스케줄러는 API 프로세스의 loopback 지표(
/internal/metrics)에서 최근 5분 p95를 읽어api_latency_pressure감속을 적용한다. 지표를 읽을 수 없으면 dead-letter 재처리와 보존 정리를 잠시 멈춘다.
- 기상 단기예보가 1,000행을 넘는 경우에도 한 요청으로 전체 예보를 받도록 페이지 크기를 조정했다. 요청 횟수와 실행당 원본 크기 상한은 유지한다.
- 축제의 시군구 주소 판별에 실제 행정코드를 포함하고 방문 전망의 예측 날짜를 발표 시각으로 취급하지 않도록 수정했다.
- 실패 입력은 유지 범위와 최신 원본을 기준으로 재처리한다. 제외한 원천과 대체된 관광 목록은 원본을 보존한 채 격리한다.
- 오래된 실행 중 기록을 복구하고 수집 불가 결과를 성공으로 집계하지 않는다. 정상 관광지 재처리의 불필요한 쿼리와 savepoint를 줄였다.
- 스냅샷 정리의 후보 검색을 개선하고 관측 보존 검사의 메모리와 실행 시간을 제한했다. 월간 수요와 다양성 수집은 주 1회로 줄이고 번역 배치 0으로 유료 작업을 끌 수 있다.
- 항공 월별 자료는 최근 2개월만 갱신하며 기존 이력은 보존한다. 과거 자료 수집으로 원천의 전체 최신 기준일이 뒤로 밀리지 않게 했다.
- 스케줄러를 끈 운영 배포를 지원한다. 자동 수집과 관찰 타이머 및 요청 통계의 DB 저장을 중지하고 기존 게시 데이터를 조회한다.
- 방문 전망 기본 기간을 14일에서 7일로 변경했다. 명시적인 1~30일 입력은 유지한다.
- 공식 전망이 없을 때 historical_weekday_proxy 참고 수요 지수를 제공한다. 임의의 날씨 보정과 검증되지 않은 confidence를 제거했다.
- 공지 since는 시간대 필수이며 경계 포함 조건을 유지한다. 시간대 없는 값은 422다.
- 검색어는 Unicode NFKC 정규화 후 양끝 공백을 제거한다. 공백만 있으면 422다.
- 주변 상점은 shops_limit 기본 5, 최대 20이다. 기존 외국어 전용 관광지도 실제 언어를 표시해 조회한다.
- 트렌드와 시장 SNS의 기본 원천은 YouTube다. 선택한 SNS의 지표와 최신성을 사용한다.
- 추천 days와 party_size는 선택적인 deprecated 입력이다. 적용하지 않은 예산과 조건을 응답에 표시한다.
- 수집 상한은 17개 시도와 5개 시장이다. 행정구역 개편을 반영한 현재 활성 시도는 16개이며 과거 코드는 보존한다. 성장 경보는 선택 수집을 감속하며 절대 자원 안전선을 유지한다.
- 디스크 75%부터 원천 쓰기를 중단하고 80%부터 게시를 중단한다. DB의 대응 기준은 19GiB와 20GiB다.
- 게시본 중복 저장을 막고 정규화 행으로 출처를 추적한다. 현재본과 이전 정상본 2개를 보존한다.
관측 기간과 데이터 확보 상태는 API 응답에 표시한다. 코드 변경만으로 24시간 또는 7일 운영 검증이 완료되지는 않는다.