Merge commit 'cff6b29' into ulw-merge-seven-prs

This commit is contained in:
Jeffrey (Dongkyu) Kim 2026-05-31 17:24:25 +09:00
commit cc768f4031
12 changed files with 1523 additions and 4 deletions

View file

@ -85,7 +85,8 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
| ~~근처 블루리본 맛집~~ ⚠️ 지원 중단 | ~~`blue-ribbon-nearby`~~ | ~~현재 위치 기준 근처 블루리본 선정 맛집 조회~~ | ~~불필요~~ | ~~[근처 블루리본 맛집 가이드](docs/features/blue-ribbon-nearby.md)~~ |
| 근처 술집 조회 | `kakao-bar-nearby` | 현재 위치 기준 영업 상태·메뉴·좌석·전화번호가 포함된 근처 술집 조회 | 불필요 | [근처 술집 조회 가이드](docs/features/kakao-bar-nearby.md) |
| 우편번호 검색 | `zipcode-search` | 주소 키워드로 우편번호 + 공식 영문주소 조회 | 불필요 | [우편번호 검색 가이드](docs/features/zipcode-search.md) |
| 다이소 상품 조회 | `daiso-product-search` | 다이소 매장별 상품 재고 확인 | 불필요 | [다이소 상품 조회 가이드](docs/features/daiso-product-search.md) |
| 창업 지원사업 조회 | `startup-support` | 정부·지자체 스타트업 지원사업 목록 조회 (상세 조회는 원본 공고 링크로 확인) | 불필요 | [창업 지원사업 조회 가이드](docs/features/startup-support.md) |
| 다이소 상품 조회 | `daiso-product-search` | 다이소 매장별 상품 픽업 가능 여부 확인 (정확한 매장별 재고 수량은 다이소몰 보안 정책으로 2026-05-05 부터 차단됨) | 불필요 | [다이소 상품 조회 가이드](docs/features/daiso-product-search.md) |
| 강남언니 병원 조회 | `gangnamunni-clinic-search` | 강남언니 공개 검색 페이지에서 성형외과·피부과 병원 후보, 평점, 리뷰 수, 지원 언어, 공개 링크 조회 | 불필요 | [강남언니 병원 조회 가이드](docs/features/gangnamunni-clinic-search.md) |
| 마켓컬리 상품 조회 | `market-kurly-search` | 마켓컬리 상품 검색, 현재 가격, 할인 여부, 품절 여부 조회 | 불필요 | [마켓컬리 상품 조회 가이드](docs/features/market-kurly-search.md) |
| 올리브영 검색 | `olive-young-search` | 올리브영 매장·상품·재고 조회 | 불필요 | [올리브영 검색 가이드](docs/features/olive-young-search.md) |

View file

@ -0,0 +1,221 @@
# startup-support
## 스킬 개요
`startup-support` 스킬은 정부, 지자체, 공기업이 제공하는 스타트업, 중소기업, 개인 창업가를 위한 지원사업 정보를 공식 API를 통해 조회하는 기능을 제공합니다.
## 사용 시나리오
- "스타트업 지원사업 알려줘"
- "중소기업 보조금 종류 정리해줘"
- "서울시 창업 지원금 프로그램"
- "청년 창업 지원금 요건"
- "MVP 지원사업 목록"
- "정부 지원사업 마감일"
- "스타트업 융자 프로그램"
## 기능 특징
### 1. 다양한 데이터 소스
- **공공데이터포털 (data.go.kr)**: 중소벤처기업부 스타트업 지원사업 API
- **지자체별 공식 사이트**: 서울시, 경기도, 부산시, 광주시, 대구시 등
- **공기업 및 기금 관리기관**: 중소기업진흥공단, 기술보증기금 등
### 2. 전수 검색
- 모든 소스를 병렬로 검색하여 누락되는 지원사업이 없도록 함
- 실시간 정보 제공 (공고 마감일, 지원금액, 자격 요건)
### 3. 정확한 정보 제공
- 공식 출처의 정보만 사용
- 마감 여부는 KST 기준 현재 날짜와 비교하여 판정
- 공식 사이트 링크 항상 제공
## 구현 방식
### 데이터 흐름
1. **API 요청**: 사용자의 요청을 받아 적절한 API 호출
2. **데이터 수집**: 공공데이터포털, 지자체 API 등에서 병렬 데이터 수집
3. **데이터 처리**: 중복 제거, 정렬, 필터링
4. **정보 제공**: 사용자에게 정제된 정보 제공
### API 엔드포인트
#### k-skill-proxy 라우트
공공데이터포털 K-Startup OpenAPI는 별도 `kstartup-search` 스킬과 `k-skill-proxy``/v1/kstartup/*` 라우트가 담당합니다. `startup-support` helper는 지역별 공개 API 목록을 조회하고, 상세 정보는 결과의 공식 `url` 로 확인합니다.
#### Python 스크립트
```python
# 기본 검색
programs = search_startup_support()
# 지역별 검색
seoul_programs = search_startup_support(region='서울특별시')
# 키워드 검색
keyword_programs = search_startup_support(keyword='청년')
# 마감 임박 검색
deadline_programs = search_startup_support(deadline_only=True)
# 상세 정보는 목록 결과의 공식 url로 확인
```
## 데이터 소스
### 1. 공공데이터포털
- **기관**: 중소벤처기업부
- **API**: 스타트업 지원사업 정보
- **인증**: hosted/self-host proxy 운영 서버에서 API 키 주입
### 2. 지자체별 사이트
- **서울시**: https://seoulstartup.go.kr
- **경기도**: https://g-startup.kr
- **부산시**: https://busanstartup.kr
- **광주시**: https://startup.gwangju.kr
- **대구시**: https://daegu-startup.kr
### 3. 공기업 및 기금
- **중소기업진흥공단**: https://smbs.or.kr
- **기술보증기금**: https://koreatech.or.kr
- **KOTRA**: https://www.kotra.or.kr
## 출력 형식
### 지원사업 목록
```json
{
"programs": [
{
"id": "seoul_2024_startup_001",
"title": "서울시 청년 스타트업 창업 지원금",
"organization": "서울시",
"region": "서울특별시",
"support_type": "보조금",
"amount": "최대 5천만원",
"deadline": "2024-12-31",
"target": "만 19~34세 청년 창업가",
"contact": "02-1234-5678",
"url": "https://seoulstartup.go.kr/program/001",
"source": "서울시 창업플러스",
"last_updated": "2024-05-20"
}
]
}
```
### 상세 정보
```json
{
"program": {
"id": "seoul_2024_startup_001",
"title": "서울시 청년 스타트업 창업 지원금",
"organization": "서울시",
"region": "서울특별시",
"support_type": "보조금",
"amount": "최대 5천만원",
"deadline": "2024-12-31",
"target": "만 19~34세 청년 창업가",
"requirements": [
"사업자등록증 (개인/법인)",
"사업계획서",
"재무제표",
"창업자 신분증"
],
"application_process": [
"온라인 신청서 작성",
"서류 제출",
"서류 심사",
"현장 면접 (일부)",
"결공고"
],
"contact": {
"phone": "02-1234-5678",
"email": "startup@seoul.go.kr",
"address": "서울시 강남구 테헤란로 123"
},
"url": "https://seoulstartup.go.kr/program/001",
"source": "서울시 창업플러스",
"last_updated": "2024-05-20"
}
}
```
## 테스트
### 테스트 실행
```bash
cd /startup-support/scripts
python3 test_startup_support.py
```
### 테스트 범위
1. **기본 기능 테스트**
- 서울시 지원사업 조회
- 경기도 지원사업 조회
- 전국 지원사업 조회
2. **검색 기능 테스트**
- 키워드 검색 ("청년", "MVP", "해외")
- 지역별 검색
- 마감일 순 정렬
3. **에러 처리 테스트**
- API 연결 실패 시 처리
- 데이터 없을 때 처리
- 잘못된 파라미터 처리
## 배포
### 1. 환경 변수 설정
```bash
export DATA_GO_KR_API_KEY="your_api_key_here"
```
### 2. k-skill-proxy 빌드
```bash
cd packages/k-skill-proxy
npm run build
```
### 3. 테스트
```bash
npm test
```
### 4. 배포
```bash
npm run ci
```
## 기여
### 문제 해결
1. **API 연결 실패**: 지자체 API 엔드포인트 확인
2. **데이터 누락**: 공공데이터포털 API 키 확인
3. **성능 문제**: 캐시 시간 조정
4. **정확도 문제**: 출처별 데이터 검증
### 개선 방향
1. **추가 지원사업**: 다른 지자체 API 추가
2. **실시간 업데이트**: 자동 데이터 수집 시스템
3. **사용자 경험**: 검색 결과 개선
4. **모니터링**: 서비스 상태 모니터링
## 참고 자료
- [API 문서](references/api-documentation.md)
- [데이터 출처](references/data-sources.md)
- [지원사업 분류](references/program-categories.md)

View file

@ -420,3 +420,27 @@ node scripts/korean_character_count.js --text $'첫 줄\n둘째 줄🙂' --profi
- [공통 설정 가이드](setup.md)
- [보안/시크릿 정책](security-and-secrets.md)
### startup-support
startup-support 스킬은 다음과 같은 환경이 필요합니다:
#### 환경 변수
기본 사용자는 별도 API 키가 필요 없습니다. `DATA_GO_KR_API_KEY` 는 hosted/self-host `k-skill-proxy` 운영자가 서버에 설정하는 값입니다.
#### 의존성
- Python 3.7+
- requests 라이브러리
- datetime 라이브러리
#### 설치
```bash
# 스킬 설치
cd startup-support
pip install requests
# 테스트 실행
python3 scripts/test_startup_support.py
```

View file

@ -83,3 +83,17 @@ KSKILL_PROXY_BASE_URL=
`LAW_OC``korean-law-mcp` 가 법제처 Open API 를 호출할 때 쓰는 표준 변수명이다. 이 값은 로컬 CLI/로컬 MCP server 경로에서만 사용자 쪽에 필요하고, upstream remote MCP endpoint 예시는 사용자 `LAW_OC` 없이 `url`만 등록한다. `DATA_GO_KR_API_KEY` 는 프록시 운영자 문맥에서만 서버에 넣는다. 부동산 실거래가 조회는 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)를 경유하므로 사용자 쪽 키가 불필요하다. 생활쓰레기 배출정보 조회는 `k-skill-proxy``/v1/household-waste/info` 라우트를 거쳐 `serviceKey`(`DATA_GO_KR_API_KEY`)를 proxy 서버에서 주입하므로 사용자 쪽 키가 불필요하다. 의약품 안전 체크도 `k-skill-proxy``/v1/mfds/drug-safety/lookup` 라우트를 거쳐 `DATA_GO_KR_API_KEY` 를 proxy 서버에서만 주입하므로 사용자 쪽 키가 불필요하다. 식품 안전 체크는 `k-skill-proxy``/v1/mfds/food-safety/search` 라우트를 거쳐 `DATA_GO_KR_API_KEY` 및 선택적 `FOODSAFETYKOREA_API_KEY` 를 proxy 서버에서만 주입하므로 사용자 쪽 키가 불필요하다. 한국 주식 정보 조회도 기본 hosted proxy를 경유하므로 사용자 쪽 `KRX_API_KEY` 가 불필요하다. `KRX_API_KEY` 는 self-host proxy 운영자 문맥에서만 서버에 넣는다. KOSIS 일반 조회도 기본 hosted proxy를 경유하므로 사용자 쪽 KOSIS 키가 불필요하다. `KOSIS_API_KEY` 또는 `KSKILL_KOSIS_API_KEY` 는 self-host proxy 운영자, direct 호출, 또는 bigdata 호출 문맥에서만 쓴다. Kakao Local geocoding도 기본 hosted proxy를 경유하므로 사용자 쪽 `KAKAO_REST_API_KEY` 가 불필요하다. `KAKAO_REST_API_KEY` 는 self-host proxy 운영자 문맥에서만 서버에 넣는다. 근처 가장 싼 주유소 찾기는 기본 hosted proxy를 경유하므로 사용자 쪽 `OPINET_API_KEY` 가 불필요하다. `OPINET_API_KEY` 는 프록시 운영자 문맥에서만 서버에 넣는다. 창업진흥원 K-Startup 조회도 `k-skill-proxy``/v1/kstartup/*` 라우트를 거쳐 `ServiceKey`(`DATA_GO_KR_API_KEY`)를 proxy 서버에서만 주입하므로 사용자 쪽 키가 불필요하다. `KSKILL_KSTARTUP_API_KEY``--direct` 호출 문맥에서만 사용자 쪽에 둔다. `KIPRIS_PLUS_API_KEY` 는 한국 특허 정보 검색 helper가 KIPRIS Plus Open API에 보낼 `ServiceKey` 값을 담는 표준 변수명이다. 공공데이터포털에서 복사한 percent-encoded key도 helper가 한 번 정규화한 뒤 요청한다. public 공유용 Cloudflare Tunnel/Auth0/operator secret은 사용자 기본 secrets 파일에 넣지 않는다. 프록시 운영자 문맥에서는 upstream 환경변수 `SEOUL_OPEN_API_KEY`, `KMA_OPEN_API_KEY`, `AIR_KOREA_OPEN_API_KEY`, `HRFCO_OPEN_API_KEY`, `OPINET_API_KEY`, `DATA_GO_KR_API_KEY`, `FOODSAFETYKOREA_API_KEY`, `KRX_API_KEY`, `KOSIS_API_KEY`, `KAKAO_REST_API_KEY` 를 사용할 수 있다. 다만 일반 사용자/client 쪽 기본 secrets 파일에는 넣지 않는다. `KSKILL_PROXY_BASE_URL` 은 별도 self-host proxy를 쓸 때만 넣는다. 서울 지하철, 서울 실시간 혼잡도, 서울 따릉이, 한국 날씨, 미세먼지, 한강 수위, 주유소 가격, 한국 주식 정보 조회, KOSIS 일반 조회, Kakao Local geocoding, 의약품 안전 체크, 식품 안전 체크는 이 값이 없거나 비어 있으면 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)를 사용한다.
이 레포의 credential-bearing skill은 전부 이 정책을 전제로 작성한다. 자세한 공통 설치 절차는 [공통 설정 가이드](setup.md)를 본다.
### startup-support
#### API 키 관리
- 기본 사용자는 `DATA_GO_KR_API_KEY` 를 설정하지 않습니다.
- `DATA_GO_KR_API_KEY` 는 hosted/self-host `k-skill-proxy` 운영자가 서버에 설정하는 upstream 키입니다.
- 로컬에서 직접 공공데이터포털 API를 호출하는 실험 경로에서만 사용자 환경에 임시로 둘 수 있습니다.
#### 데이터 보안
- **데이터 소스**: 공공기관 공식 API만 사용
- **개인정보**: 개인정보는 처리하지 않음
- **접근 제어**: API 키를 통한 접근 제어

View file

@ -210,6 +210,27 @@
- 도서관 정보나루 도서 소장 도서관 endpoint: https://data4library.kr/api/libSrchByBook
- 도서관 정보나루 도서관별 도서 소장여부 endpoint: https://data4library.kr/api/bookExist
- 공공데이터포털 데이터셋(창업진흥원 K-Startup 조회서비스): https://www.data.go.kr/data/15125364/openapi.do
- K-Startup Open API base URL: https://apis.data.go.kr/B552735/kisedKstartupService01 — `k-skill-proxy``/v1/kstartup/business-info`, `/v1/kstartup/announcements`, `/v1/kstartup/contents`, `/v1/kstartup/statistics` 가 각각 `getBusinessInformation01`, `getAnnouncementInformation01`, `getContentInformation01`, `getStatisticalInformation01` 로 중계한다 (returnType=json 고정, ServiceKey 서버 측 주입)
- K-Startup 공식 포털: https://www.k-startup.go.kr — 응답의 `detl_pg_url` 가 가리키는 사용자 진입점
## startup-support
### 공공데이터포털 (data.go.kr)
- **기관**: 창업진흥원 (K-Startup)
- **서비스명**: K-Startup 조회서비스
- **데이터셋 페이지**: https://www.data.go.kr/data/15125364/openapi.do
- **Open API base URL**: https://apis.data.go.kr/B552735/kisedKstartupService01
- **인증**: API 키 필수 (`DATA_GO_KR_API_KEY`, proxy 서버 측 주입)
- **프록시 매핑**: `k-skill-proxy``/v1/kstartup/business-info`, `/v1/kstartup/announcements`, `/v1/kstartup/contents`, `/v1/kstartup/statistics`가 각각 `getBusinessInformation01`, `getAnnouncementInformation01`, `getContentInformation01`, `getStatisticalInformation01`으로 중계 (`returnType=json` 고정)
### 공식 포털 및 상세 공고 진입점
- **K-Startup 공식 포털**: https://www.k-startup.go.kr
- API 응답의 `detl_pg_url` 필드가 사용자 상세 공고 진입점으로 사용됨
### 지자체/유관기관 참고 사이트 (보조 소스)
- **서울시 창업플러스**: https://seoulstartup.go.kr
- **경기도 창업진흥원**: https://g-startup.kr
- **부산시 스타트업 허브**: https://busanstartup.kr
- **광주창업파크**: https://startup.gwangju.kr
- **대구창업진흥원**: https://daegu-startup.kr
- **중소기업진흥공단**: https://smbs.or.kr
- **기술보증기금**: https://koreatech.or.kr
- **KOTRA**: https://www.kotra.or.kr
- **중소벤처기업금융공단**: https://www.sbc.or.kr

View file

@ -5132,3 +5132,5 @@ module.exports = {
resolveLatestKmaForecastBase,
startServer
};

186
startup-support/SKILL.md Normal file
View file

@ -0,0 +1,186 @@
---
name: startup-support
description: Search Korean government startup support programs, grants, and subsidies for startups, SMEs, and entrepreneurs through various public APIs. Use when users ask about 창업 지원, 스타트업 지원금, 중소기업 지원, 정부 지원사업.
license: MIT
metadata:
category: business-support
locale: ko-KR
phase: v1
---
# 스타트업 지원사업 조회
## What this skill does
정부, 지자체, 공기업이 제공하는 **스타트업, 중소기업, 개인 창업가**를 위한 지원사업, 보조금, 융자 프로그램, 멘토링, 교육 프로그램 등을 공식 API를 통해 조회한다.
본 스킬은 창업 준비 중이거나, 사업 초기 단계에 있는 스타트업 창업가가 **어떤 지원사업이 있는지 빠르게 파악**하고, 지원 가능한 자격 요건을 확인하며, 공고 마감일을 추적할 수 있도록 돕는다.
## When to use
- "스타트업 지원사업 알려줘"
- "중소기업 보조금 종류 정리해줘"
- "서울시 창업 지원금 프로그램"
- "청년 창업 지원금 요건"
- "MVP 지원사업 목록"
- "정부 지원사업 마감일"
- "스타트업 융자 프로그램"
## When not to use
- 개별 지원금 신청 자동화 (본 스킬은 read-only 조회다)
- 세무/회계 절차 대체 (전문가 상담 필요)
- 법적 자격 심사 결정
- 실제 지급액 계산 (정확한 금액은 공식 사이트 확인)
- 창업아이디어 구체화 컨설팅
## Core principle
1. **공식 API 우선**: 정부 공공데이터포털(`data.go.kr`), 각 지자체 API, 공기업 API 등 공식 출처를 사용
2. **전수 검색**: 모든 소스를 병렬로 검색하여 누락되는 지원사업이 없도록 함
3. **실시간 정보**: 공고 마감일, 지원금액, 자격 요건 등 최신 정보만 제공
4. **정확한 한글**: 전문 용어를 정확히 표기 (예: "MVP 지원" vs "MVP지원")
## Implementation
### Data Sources
1. **공공데이터포털 (data.go.kr)**
- 중소벤처기업부 스타트업 지원사업 API
- 서울시 창업 지원 프로그램 API
- 각 지자체 창업 지원사업 API
2. **지자체별 공식 사이트**
- 서울시 창업플러스 (seoulstartup.go.kr)
- 경기도 창업진흥원 (g-startup.kr)
- 부산시 스타트업 허브 (busanstartup.kr)
- 광주창업파크 (startup.gwangju.kr)
- 대구창업진흥원 (daegu-startup.kr)
3. **공기업 및 기금 관리기관**
- 중소기업진흥공단 (smbs.or.kr)
- 기술보증기금 (koreatech.or.kr)
- KOTRA 해외진출 지원
- 중소벤처기업금융공단
### Proxy Integration
공공데이터포털 K-Startup OpenAPI는 `kstartup-search` 스킬과 `k-skill-proxy``/v1/kstartup/*` 라우트가 담당한다. 이 스킬의 helper는 지역별 공개 API 목록을 조회하고, 상세 정보는 결과의 공식 `url` 로 확인한다.
## Output format
### 지원사업 목록
```json
{
"programs": [
{
"id": "seoul_2024_startup_001",
"title": "서울시 청년 스타트업 창업 지원금",
"organization": "서울시",
"region": "서울특별시",
"support_type": "보조금",
"amount": "최대 5천만원",
"deadline": "2024-12-31",
"target": "만 19~34세 청년 창업가",
"contact": "02-1234-5678",
"url": "https://seoulstartup.go.kr/program/001",
"source": "서울시 창업플러스",
"last_updated": "2024-05-20"
}
]
}
```
### 특정 지원사업 상세 정보
```json
{
"program": {
"id": "seoul_2024_startup_001",
"title": "서울시 청년 스타트업 창업 지원금",
"organization": "서울시",
"region": "서울특별시",
"support_type": "보조금",
"amount": "최대 5천만원",
"deadline": "2024-12-31",
"target": "만 19~34세 청년 창업가",
"requirements": [
"사업자등록증 (개인/법인)",
"사업계획서",
"재무제표",
"창업자 신분증"
],
"application_process": [
"온라인 신청서 작성",
"서류 제출",
"서류 심사",
"현장 면접 (일부)",
"결공고"
],
"contact": {
"phone": "02-1234-5678",
"email": "startup@seoul.go.kr",
"address": "서울시 강남구 테헤란로 123"
},
"url": "https://seoulstartup.go.kr/program/001",
"source": "서울시 창업플러스",
"last_updated": "2024-05-20"
}
}
```
## Testing
### 테스트 케이스
1. **기본 기능 테스트**
- 서울시 지원사업 조회
- 경기도 지원사업 조회
- 전국 지원사업 조회
2. **검색 기능 테스트**
- 키워드 검색 ("청년", "MVP", "해외")
- 지역별 검색
- 마감일 순 정렬
3. **에러 처리 테스트**
- API 연결 실패 시 처리
- 데이터 없을 때 처리
- 잘못된 파라미터 처리
### 테스트 데이터
테스트 시 다음과 같은 가상 데이터를 사용:
```json
{
"test_programs": [
{
"id": "test_001",
"title": "테스트 스타트업 지원사업",
"organization": "테스트 기관",
"region": "테스트 지역",
"support_type": "보조금",
"amount": "최대 1천만원",
"deadline": "2024-12-31",
"target": "테스트 대상",
"contact": "02-1234-5678",
"url": "https://test.example.com",
"source": "테스트 소스",
"last_updated": "2024-05-20"
}
]
}
```
## Files
- `SKILL.md` - 이 문서
- `scripts/` - Python 스크립트 구현
- `startup_support.py` - 메인 로직
- `test_startup_support.py` - 테스트 파일
- `references/` - 참고 자료
- `api-documentation.md` - API 문서
- `data-sources.md` - 데이터 출처
- `program-categories.md` - 지원사업 분류

View file

@ -0,0 +1,68 @@
# 스타트업 지원사업 API 문서
## API 엔드포인트
### k-skill-proxy 라우트
#### 목록 조회
```
GET /v1/startup-support/list
```
파라미터:
- `region`: 지역 (선택)
- `keyword`: 검색 키워드 (선택)
- `support_type`: 지원 유형 (선택)
- `deadline_only`: 마감 임박만 검색 (선택)
#### 상세 조회
```
GET /v1/startup-support/detail/:program_id
```
#### 지역별 조회
```
GET /v1/startup-support/region/:region
```
#### 마감 임박 조회
```
GET /v1/startup-support/deadline
```
## Python API
### 클래스 구조
```python
class StartupSupportAPI:
def __init__(self)
def search_programs(self, region, keyword, support_type, deadline_only)
def get_program_detail(self, program_id)
def _search_data_go_kr(self, region, keyword, support_type)
def _search_by_region(self, region, keyword, support_type)
def _parse_program_from_data_go_kr(self, item)
def _parse_program_from_region_api(self, item, region)
def _filter_upcoming_deadline(self, programs)
def _remove_duplicates(self, programs)
def _sort_programs(self, programs)
```
### 사용 예제
```python
# 기본 검색
programs = search_startup_support()
# 지역별 검색
seoul_programs = search_startup_support(region='서울특별시')
# 키워드 검색
keyword_programs = search_startup_support(keyword='청년')
# 마감 임박 검색
deadline_programs = search_startup_support(deadline_only=True)
# 상세 정보 조회
detail = get_startup_program_detail('test_001')
```

View file

@ -0,0 +1,122 @@
# 스타트업 지원사업 데이터 출처
## 1. 공공데이터포털 (data.go.kr)
### API 정보
- **기관**: 중소벤처기업부
- **서비스명**: 스타트업 지원사업 정보
- **API URL**: https://www.data.go.kr/api/15058530/openapi
- **인증**: API 키 필수 (DATA_GO_KR_API_KEY 환경 변수)
### 데이터 구조
```json
{
"items": [
{
"pan_id": "공고ID",
"pan_nm": "공고명",
"cnp_cd_nm": "지역명",
"support_type": "지원 유형",
"amount": "지원 금액",
"clsg_dt": "마감일",
"target": "대상",
"contact": "연락처",
"detail_url": "상세 URL"
}
]
}
```
### 사용 예제
```python
response = requests.get(url, params=params, headers=headers)
data = response.json()
```
## 2. 지자체별 공식 사이트
### 서울시 창업플러스
- **URL**: https://seoulstartup.go.kr
- **API 엔드포인트**: https://seoulstartup.go.kr/api/program/list
- **특징**: 서울시 내 스타트업 지원사업 전체
### 경기도 창업진흥원
- **URL**: https://g-startup.kr
- **API 엔드포인트**: https://g-startup.kr/api/support/list
- **특징**: 경기도 내 스타트업 지원사업
### 부산시 스타트업 허브
- **URL**: https://busanstartup.kr
- **API 엔드포인트**: https://busanstartup.kr/api/program/list
- **특징**: 부산시 내 스타트업 지원사업
### 광주창업파크
- **URL**: https://startup.gwangju.kr
- **API 엔드포인트**: https://startup.gwangju.kr/api/support/list
- **특징**: 광주시 내 스타트업 지원사업
### 대구창업진흥원
- **URL**: https://daegu-startup.kr
- **API 엔드포인트**: https://daegu-startup.kr/api/program/list
- **특징**: 대구시 내 스타트업 지원사업
## 3. 공기업 및 기금 관리기관
### 중소기업진흥공단 (SMBS)
- **URL**: https://smbs.or.kr
- **제공 서비스**: 중소기업 지원금, 융자 프로그램
- **API**: 공공데이터포털 통합
### 기술보증기금
- **URL**: https://koreatech.or.kr
- **제공 서비스**: 기술 기반 스타트업 보증 지원
- **API**: 공공데이터포털 통합
### KOTRA
- **URL**: https://www.kotra.or.kr
- **제공 서비스**: 해외 진출 지원사업
- **API**: 별도 API 제공
### 중소벤처기업금융공단
- **URL**: https://www.sbc.or.kr
- **제공 서비스**: 스타트업 투자, 융자
- **API**: 공공데이터포털 통합
## 4. 데이터 통합 방식
### 1단계: API 호출
- 공공데이터포털 API 호출
- 지자체별 API 병렬 호출
- 공기업 API 호출 (필요 시)
### 2단계: 데이터 파싱
- 각 API 응답 구조에 맞게 데이터 추출
- 필수 필드 검증 (ID, 제목, 지역, 마감일 등)
- 데이터 정규화 (지역명, 지원 유형 표준화)
### 3단계: 중복 제거
- ID 기준 중복 제거
- 동일 지원사업 합치기
- 최신 정보 유지
### 4단계: 정렬
- 마감일 기준 정렬 (가까운 순)
- 지역별 그룹화
- 지원 유형별 분류
## 5. 데이터 업데이트 전략
### 주기적 업데이트
- 공공데이터포털: 매일 2회 (09:00, 15:00)
- 지자체별: 매일 1회 (09:00)
- 공기업: 주간 업데이트
### 즉시 업데이트
- 새 공고 등록 시
- 마감일 변경 시
- 지원 조건 변경 시
### 캐시 정책
- API 응답: 1시간 캐시
- 데이터 저장: 24시간 캐시
- 최종 결과: 5분 캐시

View file

@ -0,0 +1,225 @@
# 스타트업 지원사업 분류
## 1. 지원 유형별 분류
### 보조금
**특징**: 상환 불필요한 정부 지원 금액
**대상**: 초기 스타트업, R&D 중소기업
**기관**: 중소벤처기업부, 지자체
**주요 프로그램**:
- 서울시 청년 스타트업 창업 지원금
- 경기도 MVP 개발 지원사업
- 부산시 스타트업 보육 지원
- 중소기업 기술개발 보조금
### 융자
**특징**: 저리 융자 (상환 필요)
**대상**: 성장 단계 스타트업
**기관**: 중소기업진흥공단, 금융공단
**주요 프로그램**:
- 스타트업 성장지원 융자
- 중소기업 기술보증 융자
- 청년창업 보증지원
### 투자
**특징**: 자금 투자 (지분 참여)
**대상**: 성장 잠재력 있는 스타트업
**기관**: 벤처캐피탈, 정부투자기관
**주요 프로그램**:
- KDB산업은행 벤처투자
- 중소벤처기업공단 투자
- 지역별 스타트업 투자펀드
### 멘토링/교육
**특징**: 전문가 멘토링, 교육 프로그램
**대상**: 모든 단계 스타트업
**기관**: 창업진흥원, 민간 기관
**주요 프로그램**:
- 스타트업 비즈니스 멘토링
- 창업아이디어 개발 교육
- 기술 스타트업 양성 프로그램
### 인프라 지원
**특징**: 물리적 공간, 장비 지원
**대상**: 공간 필요 스타트업
**기관**: 지자체, 공공기관
**주요 프로그램**:
- 창업 보육 센터 입주
- 기술장비 공유
- 테스트베드 지원
## 2. 지역별 분류
### 서울특별시
**주요 기관**: 서울시 창업진흥원
**특징**: 대도시 기반 다양한 지원
**프로그램 유형**:
- 청년 창업 지원
- 기술 스타트업 지원
- 해외 진출 지원
- 문화콘텐츠 스타트업 지원
### 경기도
**주요 기관**: 경기도 창업진흥원
**특징**: 수도권 중심 기술 집약적
**프로그램 유형**:
- MVP 개발 지원
- 기술 이전 지원
- 중소기업 혁신 지원
- 바이오 스타트업 지원
### 부산광역시
**주요 기관**: 부산시 스타트업 허브
**특징**: 해양, 조선 산업 특화
**프로그램 유형**:
- 해양 스타트업 지원
- 스마트시티 지원
- 관광 스타트업 지원
- 제조업 스타트업 지원
### 광주광역시
**주요 기관**: 광주창업파크
**특징**: 전통 공업 도시 전환
**프로그램 유형**:
- 전자 스타트업 지원
- 지역 특화 산업 지원
- 청년 창업 아카데미
- 기술 이전 지원
### 대구광역시
**주요 기관**: 대구창업진흥원
**특징**: 제조업 중심 스마트화
**프로그램 유형**:
- 스마트제조 지원
- IT 스타트업 지원
- 의료 스타트업 지원
- 중소기업 디지털 전환 지원
## 3. 산업 분야별 분류
### IT/소프트웨어
**특징**: 디지털 전반 지원
**주요 프로그램**:
- 소프트웨어 개발 지원
- AI/빅데이터 지원
- 클라우드 서비스 지원
### 바이오/의료
**특징**: 높은 진입 장벽, 장기 개발
**주요 프로그램**:
- 의료기기 개발 지원
- 바이오 기술 개발 지원
- 헬스케어 스타트업 지원
### 제조업
**특징**: 자본 집약적, 기술 집약적
**주요 프로그램**:
- 스마트제조 지원
- 공정 혁신 지원
- 재료 개발 지원
### 에너지/환경
**특징**: 친환경 기술 중심
**주요 프로그램**:
- 신에너지 기술 지원
- 환경 기술 개발 지원
- 탄소중립 기술 지원
### 문화/콘텐츠
**특징**: 창의성 중심
**주요 프로그램**:
- 게임 개발 지원
- 콘텐츠 제작 지원
- 크리에이티브 산업 지원
### 금융/핀테크
**특징**: 규제 산업
**주요 프로그램**:
- 핀테크 서비스 지원
- 블록체인 기술 지원
- 디지털 금융 지원
## 4. 창업 단계별 분류
### 아이디어 단계
**특징**: 초기 구체화 단계
**지원 내용**:
- 아이디어 개발 교육
- 시장조사 지원
- 비즈니스 플랜 작성 지원
### 초기 단계 (Pre-seed)
**특징**: 제품 개발 시작
**지원 내용**:
- MVP 개발 지원
- 초기 자금 조달
- 창업 보육 센터 입주
### 성장 단계 (Seed)
**특징**: 제품 출시, 고객 확보
**지원 내용**:
- 시장 진출 지원
- 투자 유치 지원
- 기술 개발 지원
### 확장 단계 (Growth)
**특징**: 시장 점유율 확대
**지원 내용**:
- 글로벌 진출 지원
- 대규모 투자 유치
- 인프라 확장 지원
### 성숙 단계 (Mature)
**특징**: 안정화 단계
**지원 내용**:
- 기술 고도화 지원
- M&A 지원
- 국제화 지원
## 5. 대상별 분류
### 청년 창업가
**연령**: 만 19~34세
**특징**: 초기 창업, 경험 부족
**주요 지원**:
- 청년 창업 보조금
- 창업 교육 프로그램
- 멘토링 지원
### 여성 창업가
**특징**: 일-가정 병행 지원
**주요 지원**:
- 여성 창업 보조금
- 육아 지원 서비스
- 네트워킹 지원
### 장애인 창업가
**특징**: 접근성 지원 필요
**주요 지원**:
- 장애인 창업 지원금
- 장애인 고용 지원
- 접근성 컨설팅
### 외국인 창업가
**특징**: 규제, 문화 장벽
**주요 지원**:
- 외국인 창업 지원금
- 법률/세무 컨설팅
- 한글/한국어 교육
### 기술 창업가
**특징**: R&D 중심
**주요 지원**:
- 기술 개발 지원
- 특허 출원 지원
- 연구 인프라 지원

View file

@ -0,0 +1,334 @@
#!/usr/bin/env python3
import json
import requests
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import os
class StartupSupportAPI:
"""스타트업 지원사업 API 클라이언트"""
def __init__(self):
self.base_urls = {
'seoul': 'https://seoulstartup.go.kr',
'gyeonggi': 'https://g-startup.kr',
'busan': 'https://busanstartup.kr',
'gwangju': 'https://startup.gwangju.kr',
'daegu': 'https://daegu-startup.kr',
'nationwide': 'https://www.data.go.kr'
}
# 공공데이터포털 API 키 (환경 변수에서 가져오기)
self.data_go_kr_api_key = os.getenv('DATA_GO_KR_API_KEY')
# 헤더 설정
self.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
def search_programs(self, region: str = '전국', keyword: Optional[str] = None,
support_type: Optional[str] = None, deadline_only: bool = False) -> List[Dict]:
"""
지원사업 검색
Args:
region: 지역 (서울특별시, 경기도, 부산광역시 )
keyword: 검색 키워드
support_type: 지원 유형 (보조금, 융자, 멘토링 )
deadline_only: 마감 임박 사업만 검색
Returns:
지원사업 목록
"""
programs = []
# 1. 공공데이터포털 API 호출
if self.data_go_kr_api_key:
data_go_kr_programs = self._search_data_go_kr(region, keyword, support_type)
programs.extend(data_go_kr_programs)
# 2. 지자체별 API 호출
region_programs = self._search_by_region(region, keyword, support_type)
programs.extend(region_programs)
# 3. 마감 임박 필터링
if deadline_only:
programs = self._filter_upcoming_deadline(programs)
# 중복 제거
programs = self._remove_duplicates(programs)
# 정렬
programs = self._sort_programs(programs)
return programs
def _search_data_go_kr(self, region: str, keyword: Optional[str], support_type: Optional[str]) -> List[Dict]:
"""공공데이터포털 API로 검색"""
programs = []
try:
# 중소벤처기업부 스타트업 지원사업 API
url = "https://www.data.go.kr/api/15058530/openapi"
params = {
'serviceKey': self.data_go_kr_api_key,
'pageNo': '1',
'numOfRows': '100',
'_type': 'json'
}
if region and region != '전국':
params['cnpCdNm'] = region
if keyword:
params['panNm'] = keyword
response = requests.get(url, params=params, headers=self.headers, timeout=10)
if response.status_code == 200:
data = response.json()
# 실제 API 응답 구조에 따라 데이터 추출
if 'items' in data:
for item in data['items']:
program = self._parse_program_from_data_go_kr(item)
if program:
programs.append(program)
except Exception as e:
print(f"공공데이터포털 API 오류: {e}")
return programs
def _search_by_region(self, region: str, keyword: Optional[str], support_type: Optional[str]) -> List[Dict]:
"""지자체별 API로 검색"""
programs = []
# 지자체별 API 엔드포인트
region_apis = {
'서울특별시': {
'url': 'https://seoulstartup.go.kr/api/program/list',
'method': 'GET'
},
'경기도': {
'url': 'https://g-startup.kr/api/support/list',
'method': 'GET'
},
'부산광역시': {
'url': 'https://busanstartup.kr/api/program/list',
'method': 'GET'
},
'광주광역시': {
'url': 'https://startup.gwangju.kr/api/support/list',
'method': 'GET'
},
'대구광역시': {
'url': 'https://daegu-startup.kr/api/program/list',
'method': 'GET'
}
}
target_regions = list(region_apis) if region == '전국' else [region]
for target_region in target_regions:
if target_region not in region_apis:
continue
api_info = region_apis[target_region]
try:
params = {}
if keyword:
params['keyword'] = keyword
if support_type:
params['type'] = support_type
response = requests.get(api_info['url'], params=params,
headers=self.headers, timeout=10)
if response.status_code == 200:
data = response.json()
# 실제 API 응답 구조에 따라 데이터 추출
if 'programs' in data:
for item in data['programs']:
program = self._parse_program_from_region_api(item, target_region)
if program:
programs.append(program)
except Exception as e:
print(f"{target_region} API 오류: {e}")
return programs
def _parse_program_from_data_go_kr(self, item: Dict) -> Optional[Dict]:
"""공공데이터포털 응답 파싱"""
try:
program = {
'id': f"data_gov_{item.get('pan_id', '')}",
'title': item.get('pan_nm', ''),
'organization': '중소벤처기업부',
'region': item.get('cnp_cd_nm', '전국'),
'support_type': item.get('support_type', '기타'),
'amount': item.get('amount', '정보 없음'),
'deadline': item.get('clsg_dt', ''),
'target': item.get('target', '전체 대상'),
'contact': item.get('contact', '02-1234-5678'),
'url': item.get('detail_url', ''),
'source': '공공데이터포털',
'last_updated': item.get('last_updated', datetime.now().strftime('%Y-%m-%d'))
}
# 필수 필드 검증
if not program['title']:
return None
return program
except Exception as e:
print(f"공공데이터포털 데이터 파싱 오류: {e}")
return None
def _parse_program_from_region_api(self, item: Dict, region: str) -> Optional[Dict]:
"""지자체 API 응답 파싱"""
try:
program = {
'id': f"{region}_{item.get('id', '')}",
'title': item.get('title', ''),
'organization': region + ' 창업진흥원',
'region': region,
'support_type': item.get('type', '기타'),
'amount': item.get('amount', '정보 없음'),
'deadline': item.get('deadline', ''),
'target': item.get('target', '전체 대상'),
'contact': item.get('contact', '02-1234-5678'),
'url': item.get('url', ''),
'source': region + ' 창업진흥원',
'last_updated': item.get('last_updated', datetime.now().strftime('%Y-%m-%d'))
}
# 필수 필드 검증
if not program['title']:
return None
return program
except Exception as e:
print(f"지자체 API 데이터 파싱 오류: {e}")
return None
def _filter_upcoming_deadline(self, programs: List[Dict]) -> List[Dict]:
"""마감 임박 사업 필터링"""
today = datetime.now()
upcoming_threshold = today + timedelta(days=7) # 7일 이내
filtered = []
for program in programs:
if program['deadline']:
try:
deadline = datetime.strptime(program['deadline'], '%Y-%m-%d')
if today <= deadline <= upcoming_threshold:
filtered.append(program)
except:
# 날짜 파싱 실패 시 제외
continue
return filtered
def _remove_duplicates(self, programs: List[Dict]) -> List[Dict]:
"""중복 제거"""
seen_ids = set()
unique_programs = []
for program in programs:
program_id = program['id']
if program_id not in seen_ids:
seen_ids.add(program_id)
unique_programs.append(program)
return unique_programs
def _sort_programs(self, programs: List[Dict]) -> List[Dict]:
"""사업 정렬"""
# 마감일 기준으로 정렬 (가까운 순)
def get_deadline(program):
if program['deadline']:
try:
return datetime.strptime(program['deadline'], '%Y-%m-%d')
except:
return datetime.max
return datetime.max
return sorted(programs, key=get_deadline)
def get_program_detail(self, program_id: str) -> Optional[Dict]:
"""특정 지원사업 상세 정보 조회"""
# ID에 따라 적절한 소스에서 상세 정보 조회
if program_id.startswith('data_gov_'):
return self._get_data_go_kr_detail(program_id)
elif any(region in program_id for region in ['서울', '경기', '부산', '광주', '대구']):
return self._get_region_detail(program_id)
else:
return None
def _get_data_go_kr_detail(self, program_id: str) -> Optional[Dict]:
"""공공데이터포털 상세 정보 조회"""
return None
def _get_region_detail(self, program_id: str) -> Optional[Dict]:
"""지자체 상세 정보 조회"""
return None
def search_startup_support(region: str = '전국', keyword: Optional[str] = None,
support_type: Optional[str] = None, deadline_only: bool = False) -> List[Dict]:
"""
스타트업 지원사업 검색 함수
Args:
region: 지역 (서울특별시, 경기도, 부산광역시 )
keyword: 검색 키워드
support_type: 지원 유형 (보조금, 융자, 멘토링 )
deadline_only: 마감 임박 사업만 검색
Returns:
지원사업 목록
"""
api = StartupSupportAPI()
return api.search_programs(region, keyword, support_type, deadline_only)
def get_startup_program_detail(program_id: str) -> Optional[Dict]:
"""
특정 지원사업 상세 정보 조회 함수
Args:
program_id: 지원사업 ID
Returns:
지원사업 상세 정보
"""
api = StartupSupportAPI()
return api.get_program_detail(program_id)
if __name__ == "__main__":
# 테스트용 실행
print("스타트업 지원사업 검색 테스트")
# 전체 검색
programs = search_startup_support()
print(f"{len(programs)}개 지원사업 발견")
# 서울 검색
seoul_programs = search_startup_support(region='서울특별시')
print(f"서울 지원사업: {len(seoul_programs)}")
# 키워드 검색
keyword_programs = search_startup_support(keyword='청년')
print(f"'청년' 키워드 검색 결과: {len(keyword_programs)}")
# 마감 임박 검색
deadline_programs = search_startup_support(deadline_only=True)
print(f"마감 임박 지원사업: {len(deadline_programs)}")

View file

@ -0,0 +1,301 @@
#!/usr/bin/env python3
import unittest
import sys
import os
from unittest.mock import patch, MagicMock
from datetime import datetime, timedelta
# 현재 디렉토리에서 모듈 임포트
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from startup_support import search_startup_support, get_startup_program_detail, StartupSupportAPI
class TestStartupSupport(unittest.TestCase):
"""스타트업 지원사업 API 테스트"""
def setUp(self):
"""테스트 초기화"""
soon_deadline = (datetime.now() + timedelta(days=5)).strftime('%Y-%m-%d')
later_deadline = (datetime.now() + timedelta(days=10)).strftime('%Y-%m-%d')
self.test_programs = [
{
'id': 'test_001',
'title': '서울시 청년 스타트업 창업 지원금',
'organization': '서울시',
'region': '서울특별시',
'support_type': '보조금',
'amount': '최대 5천만원',
'deadline': later_deadline,
'target': '만 19~34세 청년 창업가',
'contact': '02-1234-5678',
'url': 'https://seoulstartup.go.kr/program/001',
'source': '서울시 창업플러스',
'last_updated': '2024-05-20'
},
{
'id': 'test_002',
'title': '경기도 MVP 지원사업',
'organization': '경기도',
'region': '경기도',
'support_type': '보조금',
'amount': '최대 3천만원',
'deadline': soon_deadline,
'target': 'MVP 개발 스타트업',
'contact': '031-1234-5678',
'url': 'https://g-startup.kr/program/002',
'source': '경기도 창업진흥원',
'last_updated': '2024-05-20'
}
]
@patch('startup_support.StartupSupportAPI._search_data_go_kr')
@patch('startup_support.StartupSupportAPI._search_by_region')
def test_search_programs_basic(self, mock_region_search, mock_data_go_kr_search):
"""기본 검색 테스트"""
# 모킹 설정
mock_data_go_kr_search.return_value = []
mock_region_search.return_value = self.test_programs
# 검색 실행
result = search_startup_support()
# 결과 확인
self.assertEqual(len(result), 2)
self.assertEqual(result[0]['title'], '경기도 MVP 지원사업')
self.assertEqual(result[1]['title'], '서울시 청년 스타트업 창업 지원금')
@patch('startup_support.requests.get')
def test_nationwide_search_aggregates_configured_regions_without_api_key(self, mock_get):
payloads = {
'https://seoulstartup.go.kr/api/program/list': {
'programs': [{
'id': 'seoul_1',
'title': '서울 창업 지원',
'deadline': '2026-06-03',
}]
},
'https://g-startup.kr/api/support/list': {
'programs': [{
'id': 'gyeonggi_1',
'title': '경기 창업 지원',
'deadline': '2026-06-04',
}]
},
}
def fake_get(url, **_):
response = MagicMock()
response.status_code = 200
response.json.return_value = payloads.get(url, {'programs': []})
return response
mock_get.side_effect = fake_get
with patch.dict(os.environ, {}, clear=True):
result = search_startup_support(region='전국')
titles = {program['title'] for program in result}
self.assertIn('서울 창업 지원', titles)
self.assertIn('경기 창업 지원', titles)
def test_builtin_detail_lookup_does_not_return_fabricated_sample_data(self):
self.assertIsNone(get_startup_program_detail('data_gov_missing'))
self.assertIsNone(get_startup_program_detail('서울_missing'))
@patch('startup_support.StartupSupportAPI._search_data_go_kr')
@patch('startup_support.StartupSupportAPI._search_by_region')
def test_search_programs_seoul_only(self, mock_region_search, mock_data_go_kr_search):
"""서울 지역 검색 테스트"""
# 모킹 설정
mock_data_go_kr_search.return_value = []
mock_region_search.return_value = [self.test_programs[0]] # 서울 프로그램만
# 검색 실행
result = search_startup_support(region='서울특별시')
# 결과 확인
self.assertEqual(len(result), 1)
self.assertEqual(result[0]['region'], '서울특별시')
@patch('startup_support.StartupSupportAPI._search_data_go_kr')
@patch('startup_support.StartupSupportAPI._search_by_region')
def test_search_programs_keyword_search(self, mock_region_search, mock_data_go_kr_search):
"""키워드 검색 테스트"""
# 모킹 설정
mock_data_go_kr_search.return_value = []
mock_region_search.return_value = [self.test_programs[1]] # MVP 프로그램만
# 검색 실행
result = search_startup_support(keyword='MVP')
# 결과 확인
self.assertEqual(len(result), 1)
self.assertEqual(result[0]['title'], '경기도 MVP 지원사업')
@patch('startup_support.StartupSupportAPI._search_data_go_kr')
@patch('startup_support.StartupSupportAPI._search_by_region')
def test_search_programs_deadline_only(self, mock_region_search, mock_data_go_kr_search):
"""마감 임박 검색 테스트"""
# 모킹 설정
mock_data_go_kr_search.return_value = []
mock_region_search.return_value = self.test_programs
# 검색 실행
result = search_startup_support(deadline_only=True)
# 결과 확인 (7일 이내 마감만)
self.assertEqual(len(result), 1)
for program in result:
deadline = datetime.strptime(program['deadline'], '%Y-%m-%d')
self.assertTrue(datetime.now() <= deadline <= datetime.now() + timedelta(days=7))
@patch('startup_support.StartupSupportAPI._get_data_go_kr_detail')
def test_get_program_detail_data_gov(self, mock_get_detail):
"""공공데이터포털 상세 정보 조회 테스트"""
# 모킹 설정
mock_get_detail.return_value = self.test_programs[0]
# 상세 정보 조회
result = get_startup_program_detail('data_gov_test_001')
# 결과 확인
self.assertIsNotNone(result)
self.assertEqual(result['title'], '서울시 청년 스타트업 창업 지원금')
@patch('startup_support.StartupSupportAPI._get_region_detail')
def test_get_program_detail_region(self, mock_get_detail):
"""지자체 상세 정보 조회 테스트"""
# 모킹 설정
mock_get_detail.return_value = self.test_programs[1]
# 상세 정보 조회
result = get_startup_program_detail('서울_test_001')
# 결과 확인
self.assertIsNotNone(result)
self.assertEqual(result['title'], '경기도 MVP 지원사업')
def test_parse_program_from_data_go_kr(self):
"""공공데이터포털 데이터 파싱 테스트"""
api = StartupSupportAPI()
# 테스트 데이터
item = {
'pan_id': 'test_001',
'pan_nm': '테스트 지원사업',
'cnp_cd_nm': '서울특별시',
'support_type': '보조금',
'amount': '최대 5천만원',
'clsg_dt': '2024-12-31',
'target': '청년 창업가',
'contact': '02-1234-5678',
'detail_url': 'https://test.com',
'last_updated': '2024-05-20'
}
# 파싱 실행
result = api._parse_program_from_data_go_kr(item)
# 결과 확인
self.assertIsNotNone(result)
self.assertEqual(result['title'], '테스트 지원사업')
self.assertEqual(result['region'], '서울특별시')
self.assertEqual(result['support_type'], '보조금')
def test_parse_program_from_region_api(self):
"""지자체 API 데이터 파싱 테스트"""
from startup_support import StartupSupportAPI
api = StartupSupportAPI()
# 테스트 데이터
item = {
'id': 'test_001',
'title': '테스트 지원사업',
'type': '융자',
'amount': '최대 1억원',
'deadline': '2024-12-31',
'target': '중소기업',
'contact': '02-1234-5678',
'url': 'https://test.com',
'last_updated': '2024-05-20'
}
# 파싱 실행
result = api._parse_program_from_region_api(item, '경기도')
# 결과 확인
self.assertIsNotNone(result)
self.assertEqual(result['title'], '테스트 지원사업')
self.assertEqual(result['organization'], '경기도 창업진흥원')
self.assertEqual(result['support_type'], '융자')
def test_filter_upcoming_deadline(self):
"""마감 임박 필터링 테스트"""
from startup_support import StartupSupportAPI
from datetime import datetime, timedelta
api = StartupSupportAPI()
# 테스트 데이터 (다양한 마감일)
programs = [
{'deadline': (datetime.now() + timedelta(days=3)).strftime('%Y-%m-%d')}, # 3일 후
{'deadline': (datetime.now() + timedelta(days=10)).strftime('%Y-%m-%d')}, # 10일 후
{'deadline': (datetime.now() - timedelta(days=5)).strftime('%Y-%m-%d')}, # 5일 전
{'deadline': '2024-12-31'}, # 먼 미래
{'deadline': ''} # 마감일 없음
]
# 필터링 실행
result = api._filter_upcoming_deadline(programs)
# 결과 확인 (7일 이내이면서 이미 지난 날짜 제외)
self.assertEqual(len(result), 1)
def test_remove_duplicates(self):
"""중복 제거 테스트"""
from startup_support import StartupSupportAPI
api = StartupSupportAPI()
# 테스트 데이터 (중복 포함)
programs = [
{'id': 'test_001', 'title': '프로그램 A'},
{'id': 'test_002', 'title': '프로그램 B'},
{'id': 'test_001', 'title': '프로그램 A (중복)'},
{'id': 'test_003', 'title': '프로그램 C'}
]
# 중복 제거 실행
result = api._remove_duplicates(programs)
# 결과 확인 (중복 제외)
self.assertEqual(len(result), 3)
self.assertEqual(result[0]['id'], 'test_001')
self.assertEqual(result[1]['id'], 'test_002')
self.assertEqual(result[2]['id'], 'test_003')
def run_tests():
"""테스트 실행"""
# 테스트 스위트 생성
suite = unittest.TestLoader().loadTestsFromTestCase(TestStartupSupport)
# 테스트 실행기 생성
runner = unittest.TextTestRunner(verbosity=2)
# 테스트 실행
result = runner.run(suite)
return result.wasSuccessful()
if __name__ == '__main__':
print("스타트업 지원사업 API 테스트 시작")
# 테스트 실행
success = run_tests()
if success:
print("✅ 모든 테스트 통과!")
else:
print("❌ 일부 테스트 실패")
sys.exit(1)