chore: remove startup-support skill

This commit is contained in:
Jeffrey (Dongkyu) Kim 2026-06-05 17:21:58 +09:00
commit 46f44ed724
13 changed files with 2 additions and 998 deletions

View file

@ -93,7 +93,6 @@
"./seoul-subway-arrival",
"./sh-notice-search",
"./srt-booking",
"./startup-support",
"./subway-lost-property",
"./ticket-availability",
"./toss-securities",

View file

@ -85,7 +85,6 @@ 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) |
| 창업 지원사업 조회 | `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) |

View file

@ -1,91 +0,0 @@
# startup-support
`startup-support` helps agents answer Korean startup support-program questions by searching K-Startup announcement data through `k-skill-proxy`.
Use it for questions such as:
- "서울 청년 창업 지원사업 찾아줘"
- "모집 중인 사업화 지원 공고 알려줘"
- "이번 달 확인할 K-Startup 공고를 요약해줘"
Do not use it for application submission, legal eligibility decisions, payment automation, or grant amount calculation. The final source of truth is always the official announcement URL returned in each result.
## Data Flow
The helper calls:
```text
GET /v1/kstartup/announcements
```
It maps user-friendly terms onto the K-Startup query fields:
- `region` -> `supt_regin`
- `keyword` -> `biz_pbanc_nm`
- `support_type` -> `supt_biz_clsfc`
- `deadline_only` -> `rcrt_prgs_yn=Y`
The hosted proxy injects the data.go.kr API key. A user running the helper does not need `DATA_GO_KR_API_KEY`.
## CLI
```bash
python3 startup-support/scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--per-page 5 \
--text
```
Use dry-run when reviewing request construction without network access:
```bash
python3 startup-support/scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--dry-run
```
## Output
The helper normalizes K-Startup announcement rows into:
```json
{
"programs": [
{
"id": "A1",
"title": "서울 청년 창업 지원",
"organization": "창업진흥원",
"region": "서울",
"support_type": "사업화",
"amount": "공식 공고 확인",
"deadline": "2026-06-30",
"target": "예비창업자",
"contact": "",
"url": "https://www.k-startup.go.kr/...",
"source": "K-Startup",
"last_updated": "2026-06-01"
}
]
}
```
## Verification
```bash
python3 -m py_compile startup-support/scripts/startup_support.py startup-support/scripts/test_startup_support.py
PYTHONPATH=startup-support/scripts python3 -m unittest discover -s startup-support/scripts -p 'test_startup_support.py'
python3 startup-support/scripts/startup_support.py --region 서울특별시 --keyword 청년 --deadline-only --dry-run
```
The root `npm run ci` also compiles and runs this helper's tests.
## Failure Modes
- `400 bad_request`: invalid query parameter rejected by `k-skill-proxy`.
- `503 upstream_not_configured`: proxy lacks a configured `DATA_GO_KR_API_KEY`.
- `502 upstream_error` or `upstream_invalid_response`: data.go.kr returned an error, non-JSON body, or invalid payload.
- Empty `programs`: no matching announcements in the selected page. Broaden filters or check additional pages.

View file

@ -420,27 +420,3 @@ 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,17 +83,3 @@ 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,19 +210,6 @@
- 도서관 정보나루 도서 소장 도서관 endpoint: https://data4library.kr/api/libSrchByBook
- 도서관 정보나루 도서관별 도서 소장여부 endpoint: https://data4library.kr/api/bookExist
## 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

View file

@ -11,10 +11,10 @@
"build": "npm run build --workspaces --if-present",
"build:manus-bundle": "node scripts/build-manus-bundle.js",
"generate:plugin-manifest": "node scripts/generate-plugin-manifest.js",
"lint": "node --check scripts/skill-docs.test.js scripts/korean_character_count.js scripts/test_korean_character_count.js scripts/korean_middle_korean.js scripts/test_korean_middle_korean.js scripts/build-manus-bundle.js scripts/test_build_manus_bundle.js scripts/workflow-actions.test.js scripts/generate-plugin-manifest.js scripts/test_generate_plugin_manifest.js && python3 -m py_compile scripts/k_skill_cleaner.py scripts/test_k_skill_cleaner.py corporate-registration-consulting/scripts/fill_official_hwp.py k-skill-cleaner/scripts/k_skill_cleaner.py scripts/fine_dust.py scripts/test_fine_dust.py scripts/ktx_booking.py scripts/test_ktx_booking.py scripts/sillok_search.py scripts/test_sillok_search.py scripts/korean_spell_check.py scripts/test_korean_spell_check.py scripts/patent_search.py scripts/test_patent_search.py scripts/mfds_drug_safety.py scripts/test_mfds_drug_safety.py scripts/nts_business_registration.py scripts/test_nts_business_registration.py scripts/mfds_food_safety.py scripts/test_mfds_food_safety.py scripts/zipcode_search.py scripts/test_zipcode_search.py scripts/subway_lost_property.py scripts/test_subway_lost_property.py scripts/geeknews_search.py scripts/test_geeknews_search.py nts-business-registration/scripts/nts_business_registration.py scripts/test_naver_blog_search.py scripts/test_korean_slang_writing.py scripts/kakaotalk_mac.py scripts/test_kakaotalk_mac.py scripts/test_coupang_partners_mcp_wrapper.py scripts/test_ohou_today_deal.py scripts/ticket_availability.py scripts/test_ticket_availability.py scripts/test_danawa_price_search.py ticket-availability/scripts/ticket_availability.py coupang-product-search/scripts/coupang_partners_mcp.py ohou-today-deal/scripts/ohou_today_deal.py kakaotalk-mac/scripts/kakaotalk_mac.py naver-blog-research/scripts/_naver_http.py naver-blog-research/scripts/naver_search.py naver-blog-research/scripts/naver_read.py naver-blog-research/scripts/naver_download_images.py korean-slang-writing/scripts/_slang_http.py korean-slang-writing/scripts/slang_search.py korean-slang-writing/scripts/slang_lookup.py korean-scholarship-search/scripts/scholarship_filter.py korean-scholarship-search/scripts/test_scholarship_filter.py korean-scholarship-search/scripts/university_search_plan.py seoul-bike/scripts/seoul_bike.py scripts/test_seoul_bike.py danawa-price-search/scripts/danawa_search.py kosis-stats/scripts/run_kosis_stats.py kosis-stats/tests/test_run_kosis_stats.py kstartup-search/scripts/run_kstartup.py kstartup-search/tests/test_run_kstartup.py intercity-bus-booking/scripts/intercity_bus_search.py daangn-used-goods-search/scripts/daangn_used_goods.py daangn-realty-search/scripts/daangn_realty.py daangn-jobs-search/scripts/daangn_jobs.py daangn-cars-search/scripts/daangn_cars.py foresttrip-vacancy/scripts/run_foresttrip_vacancy.py foresttrip-vacancy/tests/test_run_foresttrip_vacancy.py startup-support/scripts/startup_support.py startup-support/scripts/test_startup_support.py && npm run lint --workspaces --if-present && ./scripts/validate-skills.sh && node scripts/generate-plugin-manifest.js --check",
"lint": "node --check scripts/skill-docs.test.js scripts/korean_character_count.js scripts/test_korean_character_count.js scripts/korean_middle_korean.js scripts/test_korean_middle_korean.js scripts/build-manus-bundle.js scripts/test_build_manus_bundle.js scripts/workflow-actions.test.js scripts/generate-plugin-manifest.js scripts/test_generate_plugin_manifest.js && python3 -m py_compile scripts/k_skill_cleaner.py scripts/test_k_skill_cleaner.py corporate-registration-consulting/scripts/fill_official_hwp.py k-skill-cleaner/scripts/k_skill_cleaner.py scripts/fine_dust.py scripts/test_fine_dust.py scripts/ktx_booking.py scripts/test_ktx_booking.py scripts/sillok_search.py scripts/test_sillok_search.py scripts/korean_spell_check.py scripts/test_korean_spell_check.py scripts/patent_search.py scripts/test_patent_search.py scripts/mfds_drug_safety.py scripts/test_mfds_drug_safety.py scripts/nts_business_registration.py scripts/test_nts_business_registration.py scripts/mfds_food_safety.py scripts/test_mfds_food_safety.py scripts/zipcode_search.py scripts/test_zipcode_search.py scripts/subway_lost_property.py scripts/test_subway_lost_property.py scripts/geeknews_search.py scripts/test_geeknews_search.py nts-business-registration/scripts/nts_business_registration.py scripts/test_naver_blog_search.py scripts/test_korean_slang_writing.py scripts/kakaotalk_mac.py scripts/test_kakaotalk_mac.py scripts/test_coupang_partners_mcp_wrapper.py scripts/test_ohou_today_deal.py scripts/ticket_availability.py scripts/test_ticket_availability.py scripts/test_danawa_price_search.py ticket-availability/scripts/ticket_availability.py coupang-product-search/scripts/coupang_partners_mcp.py ohou-today-deal/scripts/ohou_today_deal.py kakaotalk-mac/scripts/kakaotalk_mac.py naver-blog-research/scripts/_naver_http.py naver-blog-research/scripts/naver_search.py naver-blog-research/scripts/naver_read.py naver-blog-research/scripts/naver_download_images.py korean-slang-writing/scripts/_slang_http.py korean-slang-writing/scripts/slang_search.py korean-slang-writing/scripts/slang_lookup.py korean-scholarship-search/scripts/scholarship_filter.py korean-scholarship-search/scripts/test_scholarship_filter.py korean-scholarship-search/scripts/university_search_plan.py seoul-bike/scripts/seoul_bike.py scripts/test_seoul_bike.py danawa-price-search/scripts/danawa_search.py kosis-stats/scripts/run_kosis_stats.py kosis-stats/tests/test_run_kosis_stats.py kstartup-search/scripts/run_kstartup.py kstartup-search/tests/test_run_kstartup.py intercity-bus-booking/scripts/intercity_bus_search.py daangn-used-goods-search/scripts/daangn_used_goods.py daangn-realty-search/scripts/daangn_realty.py daangn-jobs-search/scripts/daangn_jobs.py daangn-cars-search/scripts/daangn_cars.py foresttrip-vacancy/scripts/run_foresttrip_vacancy.py foresttrip-vacancy/tests/test_run_foresttrip_vacancy.py && npm run lint --workspaces --if-present && ./scripts/validate-skills.sh && node scripts/generate-plugin-manifest.js --check",
"typecheck": "tsc --noEmit",
"prepare:python-test-env": "python3 -m venv .cache/python-test-venv && ./.cache/python-test-venv/bin/python -m pip install --quiet beautifulsoup4",
"test": "npm run prepare:python-test-env && node --test scripts/skill-docs.test.js scripts/test_korean_character_count.js scripts/test_korean_middle_korean.js scripts/test_build_manus_bundle.js scripts/workflow-actions.test.js scripts/test_generate_plugin_manifest.js && PYTHONPATH=.:scripts ./.cache/python-test-venv/bin/python -m unittest scripts.test_k_skill_cleaner scripts.test_fine_dust scripts.test_ktx_booking scripts.test_sillok_search scripts.test_korean_spell_check scripts.test_patent_search scripts.test_mfds_drug_safety scripts.test_nts_business_registration scripts.test_mfds_food_safety scripts.test_zipcode_search scripts.test_subway_lost_property scripts.test_geeknews_search scripts.test_naver_blog_search scripts.test_korean_slang_writing scripts.test_kakaotalk_mac scripts.test_coupang_partners_mcp_wrapper scripts.test_ohou_today_deal scripts.test_ticket_availability scripts.test_seoul_bike scripts.test_danawa_price_search && PYTHONPATH=.:scripts:korean-scholarship-search/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s korean-scholarship-search/scripts -p 'test_scholarship_filter.py' && PYTHONPATH=.:scripts:kosis-stats/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s kosis-stats/tests -p 'test_run_kosis_stats.py' && PYTHONPATH=.:scripts:kstartup-search/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s kstartup-search/tests -p 'test_run_kstartup.py' && PYTHONPATH=.:foresttrip-vacancy/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s foresttrip-vacancy/tests -p 'test_run_foresttrip_vacancy.py' && PYTHONPATH=startup-support/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s startup-support/scripts -p 'test_startup_support.py' && npm run test --workspaces --if-present && ./scripts/validate-skills.sh",
"test": "npm run prepare:python-test-env && node --test scripts/skill-docs.test.js scripts/test_korean_character_count.js scripts/test_korean_middle_korean.js scripts/test_build_manus_bundle.js scripts/workflow-actions.test.js scripts/test_generate_plugin_manifest.js && PYTHONPATH=.:scripts ./.cache/python-test-venv/bin/python -m unittest scripts.test_k_skill_cleaner scripts.test_fine_dust scripts.test_ktx_booking scripts.test_sillok_search scripts.test_korean_spell_check scripts.test_patent_search scripts.test_mfds_drug_safety scripts.test_nts_business_registration scripts.test_mfds_food_safety scripts.test_zipcode_search scripts.test_subway_lost_property scripts.test_geeknews_search scripts.test_naver_blog_search scripts.test_korean_slang_writing scripts.test_kakaotalk_mac scripts.test_coupang_partners_mcp_wrapper scripts.test_ohou_today_deal scripts.test_ticket_availability scripts.test_seoul_bike scripts.test_danawa_price_search && PYTHONPATH=.:scripts:korean-scholarship-search/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s korean-scholarship-search/scripts -p 'test_scholarship_filter.py' && PYTHONPATH=.:scripts:kosis-stats/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s kosis-stats/tests -p 'test_run_kosis_stats.py' && PYTHONPATH=.:scripts:kstartup-search/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s kstartup-search/tests -p 'test_run_kstartup.py' && PYTHONPATH=.:foresttrip-vacancy/scripts ./.cache/python-test-venv/bin/python -m unittest discover -s foresttrip-vacancy/tests -p 'test_run_foresttrip_vacancy.py' && npm run test --workspaces --if-present && ./scripts/validate-skills.sh",
"pack:dry-run": "npm pack --workspace k-lotto --dry-run && npm pack --workspace daiso-product-search --dry-run && npm pack --workspace market-kurly-search --dry-run && npm pack --workspace blue-ribbon-nearby --dry-run && npm pack --workspace kakao-bar-nearby --dry-run && npm pack --workspace cheap-gas-nearby --dry-run && npm pack --workspace public-restroom-nearby --dry-run && npm pack --workspace parking-lot-search --dry-run && npm pack --workspace court-auction-notice-search --dry-run && npm pack --workspace donation-place-search --dry-run && npm pack --workspace gongsijiga-search --dry-run && npm pack --workspace kbl-results --dry-run && npm pack --workspace kleague-results --dry-run && npm pack --workspace lck-analytics --dry-run && npm pack --workspace toss-securities --dry-run && npm pack --workspace hipass-receipt --dry-run && npm pack --workspace used-car-price-search --dry-run && npm pack --workspace k-skill-rhwp --dry-run && npm pack --workspace korean-marathon-schedule --dry-run && npm pack --workspace gangnamunni-clinic-search --dry-run && npm pack --workspace daishin-report-search --dry-run && npm pack --workspace sh-notice-search --dry-run && npm pack --workspace emergency-room-beds --dry-run && npm pack --workspace local-election-candidate-search --dry-run",
"ci": "npm run lint && npm run typecheck && npm run test && npm run pack:dry-run",
"version-packages": "changeset version",

View file

@ -1,113 +0,0 @@
---
name: startup-support
description: Search Korean K-Startup government startup support announcements through k-skill-proxy. Use when users ask about 창업 지원, 스타트업 지원금, 중소기업 지원, 정부 지원사업, or 모집 중인 창업 공고.
license: MIT
metadata:
category: business-support
locale: ko-KR
phase: v1
---
# 스타트업 지원사업 조회
## What This Skill Does
`startup-support` searches K-Startup announcement data through the hosted or self-hosted `k-skill-proxy` `/v1/kstartup/announcements` route and summarizes matching startup support programs.
Use it for:
- "서울 청년 창업 지원사업 알려줘"
- "모집 중인 사업화 지원 공고 찾아줘"
- "정부 창업 지원사업 마감일 확인해줘"
- "예비창업자 대상 K-Startup 공고 요약해줘"
Do not use it for:
- Application submission or account/payment automation
- Final legal eligibility decisions
- Inventing requirements, award amounts, contacts, or application steps not present in upstream data
- Local-government site crawling outside K-Startup
## Data Source And Credentials
- Source: 공공데이터포털 창업진흥원 K-Startup 조회서비스 (`15125364`)
- Proxy route: `/v1/kstartup/announcements`
- User credential requirement: none for normal hosted-proxy use
- Proxy operator credential: `DATA_GO_KR_API_KEY`
Set `KSKILL_PROXY_BASE_URL` or pass `--proxy-base-url` only when using a self-host proxy. For direct data.go.kr calls with a user key, use `kstartup-search` and its `--direct` mode.
## Workflow
1. Translate the user request into K-Startup announcement filters.
2. Run a small bounded search first.
3. Check each returned row's official `url` before making eligibility-sensitive claims.
4. Cite the official URL when summarizing.
Common filter mapping:
- region -> `supt_regin`
- keyword -> `biz_pbanc_nm`
- support type -> `supt_biz_clsfc`
- deadline-only / recruiting-only -> `rcrt_prgs_yn=Y`
## CLI
```bash
python3 scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--per-page 5 \
--text
```
Dry-run request construction without network or credentials:
```bash
python3 scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--dry-run
```
## Output
The helper returns:
```json
{
"programs": [
{
"id": "A1",
"title": "서울 청년 창업 지원",
"organization": "창업진흥원",
"region": "서울",
"support_type": "사업화",
"amount": "공식 공고 확인",
"deadline": "2026-06-30",
"target": "예비창업자",
"contact": "",
"url": "https://www.k-startup.go.kr/...",
"source": "K-Startup",
"last_updated": "2026-06-01"
}
]
}
```
## Failure Modes
- Empty result page: broaden filters or inspect additional pages.
- `400 bad_request`: invalid query rejected by proxy validation.
- `503 upstream_not_configured`: proxy lacks `DATA_GO_KR_API_KEY`.
- `502 upstream_error` or invalid response: data.go.kr returned an upstream error or non-JSON body.
## Maintainer Checks
```bash
python3 -m py_compile startup-support/scripts/startup_support.py startup-support/scripts/test_startup_support.py
PYTHONPATH=startup-support/scripts python3 -m unittest discover -s startup-support/scripts -p 'test_startup_support.py'
python3 startup-support/scripts/startup_support.py --region 서울특별시 --keyword 청년 --deadline-only --dry-run
```

View file

@ -1,54 +0,0 @@
# startup-support API surface
`startup-support` is a read-only helper over the existing K-Startup proxy route. It does not add independent proxy endpoints.
## Proxy route used
```text
GET /v1/kstartup/announcements
```
Common query mapping:
- `region` -> `supt_regin`
- `keyword` -> `biz_pbanc_nm`
- `support_type` -> `supt_biz_clsfc`
- `deadline_only=true` -> `rcrt_prgs_yn=Y`
- `page` -> `page`
- `per_page` -> `perPage`
Authentication is handled by hosted or self-hosted `k-skill-proxy`. Users do not pass a data.go.kr service key to this helper.
## Python helper
```python
programs = search_startup_support(
region="서울특별시",
keyword="청년",
support_type="사업화",
deadline_only=True,
)
```
The CLI exposes the same search:
```bash
python3 startup-support/scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--per-page 5 \
--text
```
For request inspection without network or credentials:
```bash
python3 startup-support/scripts/startup_support.py \
--region 서울특별시 \
--keyword 청년 \
--deadline-only \
--dry-run
```
Detailed eligibility and application steps must be confirmed from each result's official `url`.

View file

@ -1,28 +0,0 @@
# startup-support data sources
## Primary Source
- K-Startup announcement data through `k-skill-proxy` `/v1/kstartup/announcements`
- Upstream dataset: 공공데이터포털 창업진흥원 K-Startup 조회서비스 (`15125364`)
- Authentication: proxy server injects `DATA_GO_KR_API_KEY`
- Update cadence: official K-Startup/data.go.kr feed cadence, not realtime monitoring
## Helper Scope
The helper searches announcement rows and returns the official detail URL for each result. It does not crawl local-government sites directly and does not synthesize eligibility, required documents, contacts, or award amounts when upstream data omits them.
## Fallback Order
1. Hosted proxy from `KSKILL_PROXY_BASE_URL` or `https://k-skill-proxy.nomadamas.org`
2. User-provided self-host proxy via `--proxy-base-url`
3. Dry-run URL inspection when network, proxy configuration, or upstream credentials are unavailable
For direct data.go.kr calls with a user-held key, use the narrower `kstartup-search` helper's `--direct` mode.
## Failure Modes
- Empty result page: no matching K-Startup announcements for the selected filters/page.
- HTTP 400: invalid query accepted by the helper but rejected by proxy validation.
- HTTP 503: proxy has no configured `DATA_GO_KR_API_KEY`.
- HTTP 502: upstream data.go.kr error or invalid response.
- Missing detail fields: answer with the returned official URL instead of inventing requirements, amounts, or contacts.

View file

@ -1,225 +0,0 @@
# 스타트업 지원사업 분류
## 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

@ -1,283 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import ssl
import sys
import urllib.error
import urllib.parse
import urllib.request
from collections.abc import Sequence
DEFAULT_PROXY_BASE_URL = "https://k-skill-proxy.nomadamas.org"
REGION_ALIASES = {
"서울특별시": "서울",
"부산광역시": "부산",
"대구광역시": "대구",
"인천광역시": "인천",
"광주광역시": "광주",
"대전광역시": "대전",
"울산광역시": "울산",
"세종특별자치시": "세종",
"경기도": "경기",
"강원특별자치도": "강원",
"강원도": "강원",
"충청북도": "충북",
"충청남도": "충남",
"전북특별자치도": "전북",
"전라북도": "전북",
"전라남도": "전남",
"경상북도": "경북",
"경상남도": "경남",
"제주특별자치도": "제주",
}
class HelperError(RuntimeError):
pass
def _compact(value: str | None) -> str | None:
if value is None:
return None
text = value.strip()
return text or None
def _yyyymmdd_to_iso(value: str | None) -> str:
if not value:
return ""
digits = "".join(char for char in value if char.isdigit())
if len(digits) != 8:
return value
return f"{digits[0:4]}-{digits[4:6]}-{digits[6:8]}"
def build_query(args: argparse.Namespace) -> dict[str, str | int]:
if args.page < 1:
raise HelperError("--page must be >= 1")
if args.per_page < 1 or args.per_page > 100:
raise HelperError("--per-page must be in [1, 100]")
query: dict[str, str | int] = {
"page": args.page,
"perPage": args.per_page,
"returnType": "json",
}
region = _compact(args.region)
keyword = _compact(args.keyword)
support_type = _compact(args.support_type)
if region and region != "전국":
query["supt_regin"] = region
if keyword:
query["biz_pbanc_nm"] = keyword
if support_type:
query["supt_biz_clsfc"] = support_type
if args.deadline_only:
query["rcrt_prgs_yn"] = "Y"
return query
def build_url(query: dict[str, str | int], proxy_base_url: str = DEFAULT_PROXY_BASE_URL) -> str:
base = proxy_base_url.rstrip("/")
encoded = urllib.parse.urlencode([(key, str(value)) for key, value in query.items()])
return f"{base}/v1/kstartup/announcements?{encoded}"
def http_get(url: str, *, timeout: int) -> tuple[int, str, str]:
request = urllib.request.Request(
url,
headers={
"accept": "application/json",
"user-agent": "k-skill/startup-support",
},
method="GET",
)
context = ssl.create_default_context()
try:
with urllib.request.urlopen(request, timeout=timeout, context=context) as response:
body = response.read().decode("utf-8", errors="replace")
return response.status, response.headers.get("content-type", ""), body
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace") if exc.fp else ""
content_type = exc.headers.get("content-type", "") if exc.headers else ""
return exc.code, content_type, body
except urllib.error.URLError as exc:
raise HelperError(f"network error: {exc.reason}") from exc
def _rows_from_payload(payload: dict[str, object]) -> list[dict[str, object]]:
rows = payload.get("data", [])
if not isinstance(rows, list):
raise HelperError("proxy response data must be a list")
normalized: list[dict[str, object]] = []
for row in rows:
if isinstance(row, dict):
normalized.append(row)
return normalized
def _text(row: dict[str, object], *keys: str) -> str:
for key in keys:
value = row.get(key)
if value is not None and str(value).strip():
return str(value).strip()
return ""
def _canonical_region(value: str | None) -> str:
text = _compact(value)
if not text:
return ""
compacted = text.replace(" ", "")
return REGION_ALIASES.get(compacted, compacted)
def _region_parts(value: str) -> list[str]:
return [
_canonical_region(part)
for part in value.replace("/", ",").replace("|", ",").split(",")
if _canonical_region(part)
]
def _matches_region(row: dict[str, object], requested_region: str | None) -> bool:
requested = _canonical_region(requested_region)
if not requested or requested == "전국":
return True
row_region = _text(row, "supt_regin", "region")
if not row_region:
return False
return requested in _region_parts(row_region)
def _program_from_row(row: dict[str, object]) -> dict[str, str]:
program_id = _text(row, "pbanc_sn", "id")
title = _text(row, "biz_pbanc_nm", "title")
end_date = _text(row, "pbanc_rcpt_end_dt", "deadline")
return {
"id": program_id,
"title": title,
"organization": _text(row, "sprv_inst", "organization"),
"region": _text(row, "supt_regin", "region", "전국"),
"support_type": _text(row, "supt_biz_clsfc", "support_type", "기타"),
"amount": _text(row, "supt_cn", "amount", "공식 공고 확인"),
"deadline": _yyyymmdd_to_iso(end_date),
"target": _text(row, "aply_trgt", "target"),
"contact": _text(row, "biz_gdnc_url", "contact"),
"url": _text(row, "detl_pg_url", "url"),
"source": "K-Startup",
"last_updated": _yyyymmdd_to_iso(_text(row, "pbanc_rcpt_bgng_dt", "last_updated")),
}
def search_startup_support(
region: str = "전국",
keyword: str | None = None,
support_type: str | None = None,
deadline_only: bool = False,
*,
page: int = 1,
per_page: int = 10,
proxy_base_url: str | None = None,
timeout: int = 30,
) -> list[dict[str, str]]:
args = argparse.Namespace(
region=region,
keyword=keyword,
support_type=support_type,
deadline_only=deadline_only,
page=page,
per_page=per_page,
)
base_url = proxy_base_url or os.environ.get("KSKILL_PROXY_BASE_URL", DEFAULT_PROXY_BASE_URL)
url = build_url(build_query(args), proxy_base_url=base_url)
status, _, body = http_get(url, timeout=timeout)
if status < 200 or status >= 300:
raise HelperError(f"proxy returned HTTP {status}: {body[:300]}")
try:
payload = json.loads(body)
except json.JSONDecodeError as exc:
raise HelperError("proxy response was not valid JSON") from exc
if not isinstance(payload, dict):
raise HelperError("proxy response must be a JSON object")
rows = [row for row in _rows_from_payload(payload) if _matches_region(row, region)]
return [_program_from_row(row) for row in rows]
def get_startup_program_detail(program_id: str) -> None:
return None
class StartupSupportAPI:
def search_programs(
self,
region: str = "전국",
keyword: str | None = None,
support_type: str | None = None,
deadline_only: bool = False,
) -> list[dict[str, str]]:
return search_startup_support(region, keyword, support_type, deadline_only)
def get_program_detail(self, program_id: str) -> None:
return get_startup_program_detail(program_id)
def _print_text(programs: Sequence[dict[str, str]]) -> None:
if not programs:
print("일치하는 K-Startup 지원사업 공고가 없습니다.")
return
for index, program in enumerate(programs, start=1):
deadline = program["deadline"] or "마감일 공고 확인"
url = program["url"] or "상세 URL 없음"
print(f"{index}. {program['title']} | {program['region']} | {deadline}")
print(f" {url}")
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="K-Startup 창업 지원사업 공고 조회")
parser.add_argument("--region", default="전국")
parser.add_argument("--keyword")
parser.add_argument("--support-type")
parser.add_argument("--deadline-only", action="store_true")
parser.add_argument("--page", type=int, default=1)
parser.add_argument("--per-page", type=int, default=10)
parser.add_argument("--text", action="store_true")
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("--timeout", type=int, default=30)
parser.add_argument("--proxy-base-url", default=os.environ.get("KSKILL_PROXY_BASE_URL", DEFAULT_PROXY_BASE_URL))
return parser
def run(argv: Sequence[str] | None = None) -> int:
parser = build_parser()
args = parser.parse_args(argv)
try:
query = build_query(args)
url = build_url(query, proxy_base_url=args.proxy_base_url)
if args.dry_run:
print(json.dumps({"operation": "announcements", "query": query, "url": url}, ensure_ascii=False, indent=2))
return 0
programs = search_startup_support(
region=args.region,
keyword=args.keyword,
support_type=args.support_type,
deadline_only=args.deadline_only,
page=args.page,
per_page=args.per_page,
proxy_base_url=args.proxy_base_url,
timeout=args.timeout,
)
except HelperError as exc:
parser.error(str(exc))
if args.text:
_print_text(programs)
else:
print(json.dumps({"programs": programs}, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(run())

View file

@ -1,149 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import sys
import unittest
from io import StringIO
from unittest import mock
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, SCRIPT_DIR)
import startup_support # noqa: E402
def make_args(**overrides: object) -> argparse.Namespace:
defaults = {
"region": "서울특별시",
"keyword": "청년",
"support_type": None,
"deadline_only": False,
"page": 1,
"per_page": 5,
"text": False,
"dry_run": False,
"timeout": 30,
"proxy_base_url": "https://proxy.example",
}
defaults.update(overrides)
return argparse.Namespace(**defaults)
class StartupSupportHelperTests(unittest.TestCase):
def test_build_query_maps_startup_terms_to_kstartup_announcements(self) -> None:
args = make_args(deadline_only=True, support_type="사업화")
query = startup_support.build_query(args)
self.assertEqual(query["supt_regin"], "서울특별시")
self.assertEqual(query["biz_pbanc_nm"], "청년")
self.assertEqual(query["supt_biz_clsfc"], "사업화")
self.assertEqual(query["rcrt_prgs_yn"], "Y")
self.assertEqual(query["page"], 1)
self.assertEqual(query["perPage"], 5)
self.assertEqual(query["returnType"], "json")
def test_build_query_rejects_bad_page_size(self) -> None:
with self.assertRaises(startup_support.HelperError):
startup_support.build_query(make_args(per_page=0))
with self.assertRaises(startup_support.HelperError):
startup_support.build_query(make_args(per_page=101))
def test_dry_run_uses_hosted_proxy_without_requests_dependency_or_api_key(self) -> None:
out = StringIO()
with mock.patch.object(sys, "stdout", out):
rc = startup_support.run([
"--region", "서울특별시",
"--keyword", "청년",
"--deadline-only",
"--per-page", "5",
"--dry-run",
"--proxy-base-url", "https://proxy.example",
])
self.assertEqual(rc, 0)
payload = json.loads(out.getvalue())
self.assertEqual(payload["operation"], "announcements")
self.assertTrue(payload["url"].startswith("https://proxy.example/v1/kstartup/announcements?"))
self.assertIn("rcrt_prgs_yn=Y", payload["url"])
self.assertNotIn("ServiceKey", payload["url"])
def test_dry_run_uses_env_proxy_base_url_when_cli_option_is_absent(self) -> None:
out = StringIO()
with mock.patch.dict(os.environ, {"KSKILL_PROXY_BASE_URL": "https://env-proxy.example"}):
with mock.patch.object(sys, "stdout", out):
rc = startup_support.run(["--dry-run"])
self.assertEqual(rc, 0)
payload = json.loads(out.getvalue())
self.assertTrue(payload["url"].startswith("https://env-proxy.example/v1/kstartup/announcements?"))
def test_search_helper_uses_env_proxy_base_url_when_argument_is_absent(self) -> None:
payload = {"data": []}
calls = []
def fake_http_get(url: str, *, timeout: int) -> tuple[int, str, str]:
calls.append((url, timeout))
return 200, "application/json", json.dumps(payload)
with mock.patch.dict(os.environ, {"KSKILL_PROXY_BASE_URL": "https://env-proxy.example"}):
with mock.patch.object(startup_support, "http_get", side_effect=fake_http_get):
result = startup_support.search_startup_support()
self.assertEqual(result, [])
self.assertEqual(len(calls), 1)
self.assertTrue(calls[0][0].startswith("https://env-proxy.example/v1/kstartup/announcements?"))
def test_search_startup_support_parses_proxy_payload_and_filters_deadline(self) -> None:
payload = {
"data": [
{
"pbanc_sn": "A1",
"biz_pbanc_nm": "서울 청년 창업 지원",
"sprv_inst": "창업진흥원",
"supt_regin": "서울",
"supt_biz_clsfc": "사업화",
"pbanc_rcpt_bgng_dt": "20260601",
"pbanc_rcpt_end_dt": "20260630",
"aply_trgt": "예비창업자",
"detl_pg_url": "https://www.k-startup.go.kr/detail/A1",
},
{
"pbanc_sn": "B1",
"biz_pbanc_nm": "부산 청년 창업 지원",
"supt_regin": "부산",
"pbanc_rcpt_end_dt": "20260630",
"detl_pg_url": "https://www.k-startup.go.kr/detail/B1",
},
{
"pbanc_sn": "C1",
"biz_pbanc_nm": "전국 창업 지원",
"supt_regin": "전국",
"pbanc_rcpt_end_dt": "20260630",
"detl_pg_url": "https://www.k-startup.go.kr/detail/C1",
}
]
}
with mock.patch.object(startup_support, "http_get", return_value=(200, "application/json", json.dumps(payload))):
result = startup_support.search_startup_support(
region="서울특별시",
keyword="청년",
deadline_only=True,
proxy_base_url="https://proxy.example",
)
self.assertEqual(len(result), 1)
self.assertEqual(result[0]["id"], "A1")
self.assertEqual(result[0]["title"], "서울 청년 창업 지원")
self.assertEqual(result[0]["deadline"], "2026-06-30")
self.assertEqual(result[0]["url"], "https://www.k-startup.go.kr/detail/A1")
if __name__ == "__main__":
unittest.main(verbosity=2)