Skip to content
Merged

Dk #8

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ SEOUL_DATA_API_KEY=
# --- 네이버 (장소 메타데이터 보강) ---
NAVER_API_KEY=

# --- Neo4j (지식그래프 / 선택) ---
NEO4J_URI=
NEO4J_USERNAME=
NEO4J_PASSWORD=
NEO4J_DATABASE=neo4j

# --- 캐시 (선택) ---
REDIS_URL=

# --- API 운영 보호 ---
ENVIRONMENT=development
API_AUTH_TOKEN=
CORS_ALLOWED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: c4548497 | summary: Generated frontend critique artifact -->
---
target: src/api/static/index.html
total_score: 28
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: 8e71041b | summary: Generated frontend critique artifact -->
---
target: src/api/static/index.html
total_score: 31
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: 628e7afe | summary: Generated frontend critique artifact -->
---
target: src/api/static/index.html
total_score: 28
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: 40a08fd4 | summary: Generated frontend critique artifact -->
---
target: src/api/static/index.html
total_score: 31
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: 22ccaf16 | summary: Neo4j 제거, Seoul API 추가, 기술 스택·아키텍처 규칙·선결 조건 업데이트 -->
<!-- updated: 2026-09-12 | hash: 3d7c9022 | summary: Neo4j 제거, Seoul API 추가, 기술 스택·아키텍처 규칙·선결 조건 업데이트 -->
# 프로젝트: Explainable Travel Plan Validator

## 기술 스택
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: 22ccaf16 | summary: Neo4j 제거, Seoul API 추가, 기술 스택·아키텍처 규칙·선결 조건 업데이트 -->
<!-- updated: 2026-09-12 | hash: 22ccaf16 | summary: Neo4j 제거, Seoul API 추가, 기술 스택·아키텍처 규칙·선결 조건 업데이트 -->
# 프로젝트: Explainable Travel Plan Validator

## 기술 스택
Expand Down
2 changes: 1 addition & 1 deletion GEMINI.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: d6776591 | summary: 의존 방향 갱신, Neo4j Cypher injection → 범용 입력 신뢰도 검토로 교체 -->
<!-- updated: 2026-09-12 | hash: d6776591 | summary: 의존 방향 갱신, Neo4j Cypher injection → 범용 입력 신뢰도 검토로 교체 -->
# GEMINI — 시니어 엔지니어 검토자 역할 정의

## 역할
Expand Down
1 change: 1 addition & 0 deletions PRODUCT.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: b7e7ed26 | summary: Product and API notes -->
# Product

## Register
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-06-09 | hash: d14dcb5d | summary: POI 34,441건 반영·카카오 키워드 검색 폴백·추정 영업시간 강등·구현 현황 ⑰~⑲ 추가 -->
<!-- updated: 2026-09-12 | hash: d14dcb5d | summary: POI 34,441건 반영·카카오 키워드 검색 폴백·추정 영업시간 강등·구현 현황 ⑰~⑲ 추가 -->

# 관광 일정 QA 엔진 — Explainable Travel Plan Validator

Expand Down
2 changes: 1 addition & 1 deletion SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-05-07 | hash: 4c6e87f5 | summary: VRPTWEngine 파이프라인 통합 완료 — ⑯ 항목 추가, 구현 현황 16개 전체 완료 -->
<!-- updated: 2026-09-12 | hash: 4c6e87f5 | summary: VRPTWEngine 파이프라인 통합 완료 — ⑯ 항목 추가, 구현 현황 16개 전체 완료 -->

0. 실증 분석 근거 — "왜 이 시스템이 필요한가"

Expand Down
1 change: 1 addition & 0 deletions api.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- updated: 2026-09-12 | hash: 06799987 | summary: API test and integration notes -->
# API 테스트 스니펫

API 키는 `.env`에서 읽는다. 실행 전 `pip install python-dotenv requests` 필요.
Expand Down
2 changes: 1 addition & 1 deletion data_construct.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-07-30 | hash: 528a7ecf | summary: NEAR_BY 캡을 반경 300m+Top-20으로 재확정(실측 밀집도 검증) -->
<!-- updated: 2026-09-12 | hash: 528a7ecf | summary: NEAR_BY 캡을 반경 300m+Top-20으로 재확정(실측 밀집도 검증) -->

# 제주 Place 지식그래프 스키마 (Head - Relation - Tail)

Expand Down
2 changes: 1 addition & 1 deletion docs/ADR.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: 9b1cb461 | summary: ADR-005 Neo4j 제거 확정(Python M3/M4 대체), 제거 기술 표 갱신 -->
<!-- updated: 2026-09-12 | hash: 9b1cb461 | summary: ADR-005 Neo4j 제거 확정(Python M3/M4 대체), 제거 기술 표 갱신 -->
# Architecture Decision Records

## 철학
Expand Down
4 changes: 2 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: a5141bb2 | summary: Neo4j 제거, M1-M4 cluster_dispersion, 서울 도시데이터 API, 혼잡도 하이브리드 구조 반영 -->
<!-- updated: 2026-09-12 | hash: 22d55ea2 | summary: Neo4j 제거, M1-M4 cluster_dispersion, 서울 도시데이터 API, 혼잡도 하이브리드 구조 반영 -->
# 아키텍처

## 시스템 흐름
Expand Down Expand Up @@ -49,7 +49,7 @@ src/
│ └── orchestrator.py # 전체 파이프라인 오케스트레이터
└── api/
├── main.py # FastAPI app + lifespan
├── routes.py # /validate, /repair/{plan_id}, /health
├── router.py # /api/validate, /api/places, /health
└── schemas.py # ValidateRequest, ValidateResponse Pydantic 스키마
tests/
├── test_cluster_dispersion.py # M1-M4 밀집도 7개 테스트
Expand Down
2 changes: 1 addition & 1 deletion docs/DATA_COLLECTION.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: d0cb7ba4 | summary: 서울 도시데이터 API 섹션 추가, SEOUL_DATA_API_KEY 환경변수 반영 -->
<!-- updated: 2026-09-12 | hash: d0cb7ba4 | summary: 서울 도시데이터 API 섹션 추가, SEOUL_DATA_API_KEY 환경변수 반영 -->
# 데이터 파이프라인 가이드

본 시스템은 두 개의 외부 API를 데이터 소스로 사용한다:
Expand Down
2 changes: 1 addition & 1 deletion docs/ENHANCEMENT_PLAN.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: bafb1d66 | summary: 8개 요구사항 전부 ✅, M1-M4 DBSCAN 추가, 혼잡도 ⑦⑧ 신규 반영 -->
<!-- updated: 2026-09-12 | hash: bafb1d66 | summary: 8개 요구사항 전부 ✅, M1-M4 DBSCAN 추가, 혼잡도 ⑦⑧ 신규 반영 -->
# 패널티 통합 설계서 (Enhancement Plan v2)

> "**진짜 갈 수 있는 길인가**"(현실 제약) + "**얼마나 좋은 경로인가**"(품질 평가) — 6개 패널티 요구사항을 VRPTW 엔진(이미 구현)과 3개 신규 scoring 모듈로 분담 처리.
Expand Down
10 changes: 5 additions & 5 deletions docs/PRD.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: 08b17a67 | summary: Neo4j 제거, 실시간 혼잡도 MVP 포함, 기술 제약 갱신 -->
<!-- updated: 2026-09-12 | hash: 0863df04 | summary: Neo4j 제거, 실시간 혼잡도 MVP 포함, 기술 제약 갱신 -->
# PRD: Explainable Travel Plan Validator

## 목표
Expand All @@ -14,9 +14,9 @@

## 핵심 기능

1. **일정 검증** (`POST /validate`): 여행 일정 입력 → Hard Fail/Warning 탐지 → 점수 + 설명 보고서
2. **수정 제안** (`GET /repair/{plan_id}`): 검증 결과 기반 제약 수정(Repair) 제안 반환
3. **REST API**: FastAPI `/validate`, `/repair/{plan_id}`, `/health` 엔드포인트
1. **일정 검증** (`POST /api/validate`): 여행 일정 입력 → Hard Fail/Warning 탐지 → 점수 + 설명 보고서
2. **수정 제안**: 검증 응답의 `repair_suggestions` 필드로 즉시 반환
3. **REST API**: FastAPI `/api/validate`, `/api/places`, `/health` 엔드포인트

## 검증 프레임워크

Expand Down Expand Up @@ -118,7 +118,7 @@ Hard Fail 존재 시: Final Score = min(계산값, 59)
### Story 2 — 수정 제안 요청자
> "검증 결과에서 비효율적인 동선이 있었다. 자동 수정 제안을 받고 싶다."

- `GET /repair/{plan_id}` 로 Repair 제안 수신
- `POST /api/validate` 응답의 `repair_suggestions`로 Repair 제안 수신
- 우선순위: Hard Fail 제거 → 재방문 제거 → 일정 과밀 완화 → 효율 개선

### Story 3 — B2B 여행 플랫폼
Expand Down
6 changes: 3 additions & 3 deletions docs/UI_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- updated: 2026-04-30 | hash: eea4cb43 | summary: Neo4j 제거 반영 (503·health 엔드포인트 갱신) -->
<!-- updated: 2026-09-12 | hash: 2b231d35 | summary: Neo4j 제거 반영 (503·health 엔드포인트 갱신) -->
# API 설계 가이드

## 설계 원칙
Expand Down Expand Up @@ -98,7 +98,7 @@

---

### GET /repair/{plan_id}
### Repair 제안
검증된 일정의 Repair 제안 반환.

**Response** (200)
Expand Down Expand Up @@ -168,4 +168,4 @@
| 에러를 500으로 퉁치기 | 클라이언트가 원인 알 수 없음. 구체적 4xx/5xx 사용 |
| `time.sleep()` in async 함수 | `asyncio.sleep()` 사용 |
| 전역 변수에 연결 객체 저장 | FastAPI lifespan + dependency injection 사용 |
| plan_id 없이 수정 제안 반환 | /repair는 항상 /validate 이후에 호출됨. plan_id 필수 |
| 수정 제안 반환 | POST /api/validate 응답의 repair_suggestions에서 반환한다. 별도 /repair 호출은 제공하지 않는다. |
1 change: 1 addition & 0 deletions graphify-out/.graphify_detect.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions graphify-out/.graphify_python
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/Users/baiohelseu/.local/share/uv/tools/graphifyy/bin/python
1 change: 1 addition & 0 deletions graphify-out/.graphify_root
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/Users/baiohelseu/Desktop/Project/Travel-QA

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_package_json", "label": "package.json", "file_type": "code", "source_file": "package.json", "source_location": "L1"}, {"id": "$graphify-root$_package_dependencies", "label": "dependencies", "file_type": "code", "source_file": "package.json", "source_location": "L2"}, {"id": "$graphify-root$_package_dependencies_pptxgenjs", "label": "pptxgenjs", "file_type": "code", "source_file": "package.json", "source_location": "L3"}, {"id": "pptxgenjs", "label": "pptxgenjs", "file_type": "concept", "source_file": "package.json", "source_location": "L3"}], "edges": [{"source": "$graphify-root$_package_json", "target": "$graphify-root$_package_dependencies", "relation": "contains", "confidence": "EXTRACTED", "source_file": "package.json", "source_location": "L2", "weight": 1.0}, {"source": "$graphify-root$_package_dependencies", "target": "$graphify-root$_package_dependencies_pptxgenjs", "relation": "contains", "confidence": "EXTRACTED", "source_file": "package.json", "source_location": "L3", "weight": 1.0}, {"source": "$graphify-root$_package_dependencies_pptxgenjs", "target": "pptxgenjs", "relation": "imports", "confidence": "EXTRACTED", "source_file": "package.json", "source_location": "L3", "weight": 1.0, "context": "import"}]}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_gun_src_init_py", "label": "__init__.py", "file_type": "code", "source_file": "gun/src/__init__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_gun_tests_init_py", "label": "__init__.py", "file_type": "code", "source_file": "gun/tests/__init__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_src_api_main_py", "label": "main.py", "file_type": "code", "source_file": "src/api/main.py", "source_location": "L1"}, {"id": "get", "label": "get", "file_type": "code", "source_file": "", "source_location": "", "origin_file": "$graphify-root$/src/api/main.py"}, {"id": "$graphify-root$_src_api_main_index", "label": "index()", "file_type": "code", "source_file": "src/api/main.py", "source_location": "L47", "_callable": true}, {"id": "$graphify-root$_src_api_main_manifest", "label": "manifest()", "file_type": "code", "source_file": "src/api/main.py", "source_location": "L55", "_callable": true}, {"id": "response", "label": "Response", "file_type": "code", "source_file": "", "source_location": "", "origin_file": "$graphify-root$/src/api/main.py"}, {"id": "$graphify-root$_src_api_main_service_worker", "label": "service_worker()", "file_type": "code", "source_file": "src/api/main.py", "source_location": "L63", "_callable": true}, {"id": "$graphify-root$_src_api_main_health", "label": "health()", "file_type": "code", "source_file": "src/api/main.py", "source_location": "L75", "_callable": true}, {"id": "$graphify-root$_src_api_main_rationale_76", "label": "\ub77c\uc774\ube0c\ub2c8\uc2a4 + \uad6c\uc131 \uc9c4\ub2e8. \uc2dc\ud06c\ub9bf \uac12\uc740 \uc808\ub300 \ub178\ucd9c\ud558\uc9c0 \uc54a\uace0, \ud0a4 \uc124\uc815 \uc5ec\ubd80(bool)\uc640 \ub85c\ub529\ub41c \ub370\uc774\ud130 \uac74\uc218\ub9cc \ubc18\ud658\ud55c\ub2e4. \uc2ec\uc0ac \uc2dc \uc678\ubd80 API\u2026", "file_type": "rationale", "source_file": "src/api/main.py", "source_location": "L76"}], "edges": [{"source": "$graphify-root$_src_api_main_py", "target": "os", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L4", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "pathlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L5", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L7", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "fastapi_middleware_cors", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L8", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "fastapi_responses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L9", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "fastapi_staticfiles", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L10", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_py", "target": "src_api_router", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L23", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_index", "target": "get", "relation": "references", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L46", "weight": 1.0, "context": "decorator"}, {"source": "$graphify-root$_src_api_main_py", "target": "$graphify-root$_src_api_main_index", "relation": "contains", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L47", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_manifest", "target": "get", "relation": "references", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L54", "weight": 1.0, "context": "decorator"}, {"source": "$graphify-root$_src_api_main_py", "target": "$graphify-root$_src_api_main_manifest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L55", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_manifest", "target": "response", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L55", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_service_worker", "target": "get", "relation": "references", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L62", "weight": 1.0, "context": "decorator"}, {"source": "$graphify-root$_src_api_main_py", "target": "$graphify-root$_src_api_main_service_worker", "relation": "contains", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L63", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_service_worker", "target": "response", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L63", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_health", "target": "get", "relation": "references", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L74", "weight": 1.0, "context": "decorator"}, {"source": "$graphify-root$_src_api_main_py", "target": "$graphify-root$_src_api_main_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L75", "weight": 1.0}, {"source": "$graphify-root$_src_api_main_rationale_76", "target": "$graphify-root$_src_api_main_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "src/api/main.py", "source_location": "L76", "weight": 1.0}], "raw_calls": [{"caller_nid": "$graphify-root$_src_api_main_index", "callee": "exists", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L49", "receiver": "html_file"}, {"caller_nid": "$graphify-root$_src_api_main_index", "callee": "read_text", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L50", "receiver": "html_file"}, {"caller_nid": "$graphify-root$_src_api_main_manifest", "callee": "exists", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L57", "receiver": "f"}, {"caller_nid": "$graphify-root$_src_api_main_manifest", "callee": "read_text", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L58", "receiver": "f"}, {"caller_nid": "$graphify-root$_src_api_main_service_worker", "callee": "exists", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L65", "receiver": "f"}, {"caller_nid": "$graphify-root$_src_api_main_service_worker", "callee": "read_text", "is_member_call": true, "source_file": "src/api/main.py", "source_location": "L67", "receiver": "f"}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L87", "receiver": null}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L88", "receiver": null}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L89", "receiver": null}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L90", "receiver": null}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L91", "receiver": null}, {"caller_nid": "$graphify-root$_src_api_main_health", "callee": "_is_set", "is_member_call": false, "source_file": "src/api/main.py", "source_location": "L92", "receiver": null}]}
Loading
Loading