generated from ttipo/project-base
docs: 공연·전시 출처 조사와 KOPIS 동기화 설계 정리
- 조사 문서: KOPIS·한국문화정보원·대구문화예술진흥원 이용 조건·필드·한도, 사용자 확인(KOPIS 저장·포스터 재사용 가능), 2026-11-03 진단 결과 - place-db.md v1.7: 여러 출처 스키마(§2.4), KOPIS 동기화 순서·좌표 검사·호출량·알려진 한계(§12.1), 다음 출처(§12.2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+51
-9
@@ -1,7 +1,7 @@
|
||||
# 장소 DB 설계 (v1.5, 2026-11-03)
|
||||
# 장소 DB 설계 (v1.7, 2026-11-03)
|
||||
|
||||
WanderGo 의 장소·축제 데이터를 어떻게 저장하고, 갱신하고, 앱에 노출하는지 정한다.
|
||||
1단계(엔티티·마이그레이션)와 2·3단계(관광공사 국문·반려동물·상가정보 동기화 명령), 중복 병합, 조회 API(§11), 축제·행사 동기화·API(§12)를 구현했다 — `backend/src/modules/place/`, `backend/src/commands/place-sync.ts`, `backend/src/migrations/`.
|
||||
1단계(엔티티·마이그레이션)와 2·3단계(관광공사 국문·반려동물·상가정보 동기화 명령), 중복 병합, 조회 API(§11), 축제·행사 동기화·API와 KOPIS 공연 동기화(§12)를 구현했다 — `backend/src/modules/place/`, `backend/src/commands/place-sync.ts`, `backend/src/migrations/`.
|
||||
이 문서와 코드가 다르면 코드가 기준이다. 바꿀 때는 이 문서도 함께 고친다.
|
||||
|
||||
## 0. 전제 (이미 정한 것)
|
||||
@@ -152,7 +152,7 @@ erDiagram
|
||||
- 한국어는 `place` 본체에 둔다.
|
||||
- 관광공사 영문은 국문과 연결 필드가 없어 **좌표(50m 안) + 분류 코드**로 맞춘다. 맞지 않은 영문 항목은 기록만 하고 붙이지 않는다(첫 적재 때 매칭률을 잰다).
|
||||
|
||||
### 2.4 `festival_event` — 축제·공연·행사
|
||||
### 2.4 `festival_event` — 축제·공연·행사·전시
|
||||
|
||||
| 컬럼 | 설명 |
|
||||
| --- | --- |
|
||||
@@ -164,7 +164,11 @@ erDiagram
|
||||
| `i18n` | jsonb `{en: {name, overview}}` |
|
||||
| `status`, `last_seen_at` | |
|
||||
|
||||
- "60일 넘는 상시 프로그램 제외"는 **조회할 때** 적용한다(저장은 그대로).
|
||||
- "상시 프로그램 제외"는 **조회할 때** 종류별 기간 상한으로 적용한다(저장은 그대로): 축제·공연·행사 60일, 전시 183일(`EVENT_MAX_SPAN_DAYS`).
|
||||
- **여러 출처**(2026-11-03, 마이그레이션 `1793704967449-AddEventSourceAndVenue`): `source`(tour 관광공사 · kopis 공연예술통합전산망 ·
|
||||
kcisa 한국문화정보원 · dgfca 대구문화예술진흥원) + `(source, source_id)` 유니크. 종류에 `exhibition`, 장르(`genre`)·예매 링크(`booking_url`)·
|
||||
공연장(`venue_id` → `event_venue`) 추가. KOPIS 공연은 좌표가 공연장 상세에만 있어 `event_venue`(출처별 시설 id 유니크)에 캐시한다.
|
||||
- 출처별 동기화는 자기 출처 행사만 숨긴다(관광공사 동기화가 KOPIS 공연을 숨기지 않게).
|
||||
|
||||
### 2.5 `place_sync_run` — 동기화 기록
|
||||
|
||||
@@ -234,13 +238,14 @@ erDiagram
|
||||
| 반려동물 | 매주 | `detailPetTour2` contentId 없이 전체(약 9,700건, 10회) → contentid 로 붙임 | 10회 |
|
||||
| 관광공사 영문 | 매주 | 영문 `areaBasedList2` → 좌표+분류로 매칭 → `place_i18n(en)` | |
|
||||
| 상가정보 | 분기 | 대상 행정동 `storeListInDong`(divId=adongCd) × 데이트 업종 → bizesId 로 upsert. **새 스냅샷에 없는 ID → `gone`** | 도심·수성못·앞산 행정동 |
|
||||
| 축제·행사 | 매일 | `searchFestival2`(오늘−60일 ~ 오늘+60일) | |
|
||||
| 축제·행사 | 매일 | `searchFestival2`(오늘 ~ 오늘+90일, 대구+경북) | 대구 1 · 경북 7 (90일) |
|
||||
| KOPIS 공연 | 매일 | `pblprfr`(오늘 ~ 오늘+90일) → 새·바뀐 공연만 상세 → 새 공연장만 시설 상세 | 대구 153 · 경북 91 (90일) |
|
||||
| 폐업 대조 | 분기 | 행안부 인허가(휴게음식점·제과점·일반음식점) 영업상태와 주소·상호로 대조 → `gone` 후보 | 활용신청 후 |
|
||||
|
||||
- 비표출 레코드는 법정동이 비어 있으므로 비표출 확인은 지역 필터 없이 한다(매뉴얼 검토 노트).
|
||||
- 동기화는 `place` 만 쓴다. `place_curation` 은 읽지도 쓰지도 않는다.
|
||||
|
||||
### 4.1 실행 방법 (구현됨: 관광공사 국문·반려동물·상가정보)
|
||||
### 4.1 실행 방법 (구현됨: 관광공사 국문·반려동물·상가정보·축제·KOPIS 공연)
|
||||
|
||||
```bash
|
||||
# 개발 — 키가 있는 백엔드 컨테이너 안에서 (dc = docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development)
|
||||
@@ -249,6 +254,7 @@ dc exec backend npm run place:sync -- tour-kor # 대구(27) 목록
|
||||
dc exec backend npm run place:sync -- tour-pet # 반려동물 동반 정보(약 10회)
|
||||
dc exec backend npm run place:sync -- store # 상가정보 데이트 업종(대구 중구·남구·수성구, 30회 안팎). 분기마다
|
||||
dc exec backend npm run place:sync -- event # 축제·공연·행사(대구+경북, 오늘부터 90일 안). 매일. 새로 생기거나 바뀐 행사만 상세
|
||||
dc exec backend npm run place:sync -- kopis # KOPIS 공연(대구+경북, 90일). 매일. KOPIS_SERVICE_KEY 필요. 첫 실행은 상세 250회 안팎(0.6초 간격, 약 4분)
|
||||
dc exec backend npm run place:sync -- dedupe # 같은 가게 병합(키 불필요). tour-kor·store 가 끝날 때도 자동으로 돈다
|
||||
dc exec backend npm run place:sync -- reparse-hours # 저장된 영업시간 원문을 지금의 파서로 다시 해석(키 불필요). 파서를 고친 뒤 한 번
|
||||
dc exec backend npm run place:sync -- status # 적재 현황·오늘 쓴 호출 수
|
||||
@@ -377,6 +383,42 @@ node dist/commands/place-sync.js tour-kor
|
||||
- 홈 '이번 주말 축제·행사' = `from`=토 · `to`=일 · 동네 중심 좌표 · `radius`=120000 → 대구 행사가 먼저, 다음 경북(거리 표시 "대구에서 85km").
|
||||
- **비면** 같은 반경으로 `from`=오늘 · `to`=오늘+30일을 불러 제목을 '다가오는 축제·행사'로 바꿔 보여 준다(빈 칸을 두지 않는다).
|
||||
- 장소 상세 '근처 축제·행사' = 장소 좌표 + 기본 반경(5km), 없으면 칸을 숨긴다.
|
||||
- 다음 보강(조사 예정): 대구는 공연·전시가 많은데 관광공사에는 거의 없다 → 공연예술통합전산망(KOPIS)·문화체육관광부 문화정보 API 의
|
||||
이용 조건(저장 허용·출처 표시·호출 한도)을 확인한 뒤 출처로 추가한다. 운영자 직접 등록은 운영자 화면이 생기면.
|
||||
- 계약 테스트: `backend/test/festival.e2e-spec.ts`(12개) — 2030년 날짜·동해 좌표 픽스처라 실행 날짜와 무관하다.
|
||||
- 계약 테스트: `backend/test/festival.e2e-spec.ts` — 2030년 날짜·동해 좌표 픽스처라 실행 날짜와 무관하다.
|
||||
|
||||
### 12.1 KOPIS 공연 (구현됨)
|
||||
|
||||
**동기화** `place:sync -- kopis [--regions=27,47] [--days=90]` (매일, `KOPIS_SERVICE_KEY` 필요)
|
||||
|
||||
대구는 공연이 많은데 관광공사에는 거의 없다. 그래서 KOPIS 공연예술통합전산망을 공연 출처로 쓴다.
|
||||
조사: `docs/research/pre-dev-check/culture_event_sources.md`. 2026-11-03 사용자 확인: KOPIS 데이터 저장·포스터 재사용 가능.
|
||||
|
||||
- **진단**(2026-11-03, `tools/data-check/culture_api_check.py`)
|
||||
- 90일을 한 번에 조회할 수 있다(31일 제한 없음). https 동작.
|
||||
- 앞으로 90일 공연: 대구 153건(클래식 62 · 대중음악 30 · 뮤지컬 25 · 연극 16 …), 경북 91건.
|
||||
- 목록에는 공연시설 id·좌표·수정일이 없다. 그래서 상세와 시설 상세를 따로 부른다.
|
||||
- 공연시설 좌표는 5곳 중 5곳에 있었다. 다만 1곳(대구 중구 주소)이 경주 좌표였다 → 아래 좌표 검사를 만든 이유.
|
||||
- 순서(`sync/kopis.sync.ts`)
|
||||
1. **목록** `pblprfr`(signgucode, stdate=오늘, eddate=오늘+N일, rows=100). 끝난 공연(`공연완료`)·다른 시·도·중복은 건너뛴다.
|
||||
목록을 끝까지 받았으면 받은 기간 안에서 목록에 없는 공연을 숨긴다(원본 장애 판단은 §4.1).
|
||||
2. **상세** `pblprfr/{mt20id}` — 새 공연, 어제 이후 등록·수정된 공연(목록 `afterdate`), 상세를 받은 지 7일 지난 공연만.
|
||||
요금 `pcseguidance` → `fee_text`, 공연 시간 `dtguidance` → `playtime_text`, 예매처 첫 링크 → `booking_url`,
|
||||
소개 = 줄거리 `sty` + 출연·관람 시간·관람 연령 줄. 장소 이름은 상세가 홀까지 주므로("대구콘서트하우스 (그랜드홀 …)") 상세 값을 쓴다.
|
||||
3. **공연시설** `prfplc/{mt10id}` — 진행 중·예정 공연이 쓰는 시설 중 새 시설과 30일 지난 시설만 → `event_venue`.
|
||||
**좌표는 주소의 시·도 영역 안일 때만 쓴다**(`geo.ts` `isInSido`). 아니면 비우고 경고를 남긴다(그 공연은 근처 조회에서만 빠진다).
|
||||
4. 시설의 좌표·주소·전화를 공연에 복사한다. 조회 API 가 공연 좌표로 거리를 계산하기 때문이다. 시설 좌표를 고치면 다음 실행에 공연도 바뀐다.
|
||||
- 포스터는 `http://www.kopis.or.kr/…` 로 온다. 앱이 http 이미지를 막으므로 `https://kopis.or.kr/…` 로 바꿔 저장한다(목록·상세 사진 모두 포스터).
|
||||
- 호출: 0.6초 간격(KOPIS 는 초당 10회에서 차단). 오퍼레이션별(`pblprfr`·`pblprfr-detail`·`prfplc-detail`) 하루 상한 980.
|
||||
공식 한도는 밝혀져 있지 않다. 이후 하루 호출은 목록 4회 + 상세 수십 회로 예상한다.
|
||||
- 출처 표기: 조회 API 상세의 `attribution.provider` = "(재)예술경영지원센터 공연예술통합전산망(www.kopis.or.kr)".
|
||||
- 검증: `backend/test/kopis-sync.e2e-spec.ts`. 가짜 KOPIS 응답과 실제 DB 로 다음을 확인한다.
|
||||
첫 적재와 시설 좌표 복사, 틀린 좌표 비우기 → 재실행 시 상세·시설 재조회 없음 → 바뀐 공연만 상세 재조회, 없어진 공연 숨김.
|
||||
- 알려진 한계
|
||||
- 관광공사 공연(EV02)과 같은 공연이 둘 다 나올 수 있다. 출처 간 같은 행사 병합은 아직 없다(조사 문서 3-3 의 규칙으로 나중에).
|
||||
- '이번 주말'은 기간이 겹치는지만 본다. 평일만 하는 공연도 섞인다(`dtguidance` 요일 해석은 나중에).
|
||||
- 기간이 60일 넘는 공연(대구 8건)은 상시 프로그램 규칙으로 목록에서 빠진다.
|
||||
|
||||
### 12.2 다음 출처
|
||||
|
||||
- **전시: 한국문화정보원 한눈에보는문화정보**(15138937). 진단 결과 앞으로 90일 대구 42건(전시 13 · 음악/콘서트 17 …), 경북 17건(전시 1)이다. 좌표 채움 38/42.
|
||||
공연은 KOPIS 와 겹치므로 **전시(realm 전시)만** 받을 계획이다. 이미지 이용 조건은 아직 확인하지 않았다(조사 문서 4장 4번).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user