physicalai-jobs.com × humanoid-jobs.com 횡단 검색 + 본인 채용·프로필도 수정 가능한 MCP 서버.
읽기/쓰기 24 + 자동화·분석·AI 보조 12, 총 37개 도구를 Claude Code / Cursor / HTTP API 에서 호출 가능.
"AI는 사이트를 직접 보고 답할 수 있는데 왜 MCP를 거치나?"에 대한 답입니다. 일회성 질문이면 확실히 불필요하지만, 다중 사이트 횡단·정기 실행·엄밀 필터·대량 취득에서 차이가 납니다.
| 관점 | 웹 액세스(MCP 없음) | MCP 경유 |
|---|---|---|
| 데이터 형식 | LLM이 HTML 해석 | 구조화 JSON을 즉시 반환 |
| 응답 속도 | 수 초〜십수 초 | 약 100ms(DB 직접) |
| 2-사이트 횡단 | humanoid 와 physicalai 를 따로 순회 | 1요청으로 양쪽(site_code 생략) |
| 필터 정밀도 | UI 표시 가능 범위만 | salary_min / is_remote / prefecture 등 엄밀 지정 |
| 대량 취득 | 스크레이핑은 차단 우려 | offset/limit 로 안전하게 전건 |
| 사이트 개편 내성 | 레이아웃 변경 시 깨짐 | 스키마 고정으로 안정 |
| 정기 실행(cron) | 매번 브라우저 기동 → 느림·무거움 | curl 한 번이면 끝 |
즉 "지금 AI에게 한 건만 묻고 싶다"면 불필요. 자동화 워크플로에 넣고 싶다, 매일 집계하고 싶다, 2사이트를 동시에 정확히 검색하고 싶다면 MCP가 압도적으로 편합니다.
AI 에이전트가 physicalai-jobs.com / physicalai-jobs.com 의 채용 데이터를 횡단 활용하는 대표 시나리오입니다.
시나리오: "휴머노이드나 피지컬 AI에서 연봉 800만 이상 원격 채용을 찾아줘"
동작: 사이트 지정 없이 jobs_search 호출만으로 양 사이트 동시 검색.
시나리오: "Boston Dynamics 같은 기업을 모두 뽑아 기술 스택과 채용 수를 목록화"
동작: companies_search → companies_detail 로 기술 스택·모집 직종까지 취득.
시나리오: "휴머노이드 업계 최신 트렌드를 기사에서 요약"
동작: articles_search 로 기사 취득 → articles_detail 로 본문 분석.
시나리오: "휴머노이드 채용 수와 피지컬 AI 채용 수 추이를 매주 리포트"
동작: stats 를 주간 cron으로 호출해 Slack에 보내기만.
Claude Code / Cursor 등 MCP 지원 AI에서 3단계로 Jobs Navi에 연결할 수 있습니다.
/mypage/api-keys/ 에서 키 생성. 읽기만이면 건너뛰기 OK. .mcp.json) 또는 Cursor (~/.cursor/mcp.json)에 추가. env 는 키 발급자만. {
"mcpServers": {
"jobs-navi": {
"command": "npx",
"args": ["-y", "jobs-navi-mcp"],
"env": {
"JOBS_NAVI_API_KEY": "jn_your_api_key_here"
}
}
}
}
npx 경유로 jobs-navi-mcp 자동 취득. 재시작 후 37개 도구가 인식됩니다. # 읽기 예시
> 도쿄에서 로보틱스 엔지니어, 연봉 800만 이상 채용 있어?> Boston Dynamics가 지금 올린 채용 전부 알려줘
# 쓰기 예시(API 키 필요)
> 새 채용 작성: 시니어 로보틱스 엔지니어, 연봉 900〜1500만, 원격 가능> 자사 프로필 설명을 "2026년도 시리즈B 완료"로 갱신> 내 희망 연봉을 900만으로 변경, 도쿄/가나가와 희망으로
Claude Code / Cursor / HTTP API 3가지로 연결 가능. HTTP API라면 ChatGPT Custom GPT Actions 에서도 호출 가능.
.mcp.json 또는 ~/.claude.json 에 아래를 추가합니다. JOBS_NAVI_API_KEY 는 쓰기 도구 이용 시 필수(읽기 전용이면 생략 가능).
{
"jobs-navi": {
"command": "npx",
"args": ["-y", "jobs-navi-mcp"],
"env": {
"JOBS_NAVI_API_KEY": "jn_your_api_key_here"
}
}
}
~/.cursor/mcp.json 에 아래를 추가.
{
"mcpServers": {
"jobs-navi": {
"command": "npx",
"args": ["-y", "jobs-navi-mcp"],
"env": {
"JOBS_NAVI_API_KEY": "jn_your_api_key_here"
}
}
}
}
※ ChatGPT 는 Remote MCP 미지원입니다. Custom GPT Actions 에서 HTTP API 를 호출하세요.
# Custom GPT Actions 설정
# Server URL
https://physicalai-jobs.com/api/mcp.php
# Method: POST / Body 예시
{
"action": "jobs.search",
"params": { "keyword": "로보틱스" }
}
읽기는 인증 불필요, 쓰기는 Authorization: Bearer jn_xxx 가 필요합니다.
# 읽기(인증 불필요)
curl -X POST https://physicalai-jobs.com/api/mcp.php \
-H "Content-Type: application/json" \
-d '{"action": "jobs.search", "params": {"keyword": "로봇", "limit": 5}}'
# 쓰기(API 키 필수)
curl -X POST https://physicalai-jobs.com/api/mcp.php \
-H "Authorization: Bearer jn_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"action": "jobs.publish", "params": {"id": 15}}'
읽기 12개 도구는 인증 불필요. 쓰기 12개 도구(채용 작성·갱신·공개, 자사/구직자 프로필 편집 등)는 jn_xxx 형식 API 키가 필수입니다.
physicalai-jobs.com 로그인 후, /mypage/api-keys/ 키를 생성. jn_ + 48자 hex 의 51자, 최대 5개 보유 가능.
HTTP 직접 호출 시 Authorization 헤더에 부여. Node.js MCP 는 JOBS_NAVI_API_KEY 환경변수로 자동 부여됩니다.
Authorization: Bearer jn_a1b2c3d4e5f6...
API 키는 발급 사용자에 연결되므로 자사 채용 / 본인 프로필만 갱신 가능. 타사 채용은 읽기 가능·쓰기 불가.
상세 사양·다층 방어·레이트 제한은 Security / Rate Limits 섹션을 참조하세요.
전체 37개 도구 목록. 클릭하면 파라미터와 응답 예시가 펼쳐집니다. site_code 생략 시 횡단 검색.【API 키 필요】도구는 쓰기·본인 리소스 조작용.
MCP 서버 헬스 체크. 각 사이트의 채용 수·기업 수·기사 수를 반환.
파라미터 불필요.
응답 예시{
"success": true,
"data": {
"status": "ok",
"sites": [
{
"site_code": "humanoid",
"name": "ヒューマノイドジョブ",
"domain": "humanoid-jobs.com",
"job_count": 1,
"company_count": 1,
"article_count": 0
},
{
"site_code": "physicalai",
"name": "フィジカルAIジョブ",
"domain": "physicalai-jobs.com",
"job_count": 0,
"company_count": 0,
"article_count": 0
}
]
}
}
횡단 검색 대상 사이트 목록을 반환(코드·명칭·도메인·테마 컬러).
파라미터 불필요.
응답 예시{
"success": true,
"data": [
{
"site_code": "humanoid",
"name": "ヒューマノイドジョブ",
"domain": "humanoid-jobs.com",
"specialty": "ロボット・ヒューマノイド人材特化",
"theme_color": "#0EA5E9"
},
{
"site_code": "physicalai",
"name": "フィジカルAIジョブ",
"domain": "physicalai-jobs.com",
"specialty": "フィジカルAI人材特化",
"theme_color": "#0d9488"
}
]
}
채용 카테고리 목록을 채용 건수와 함께 반환.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai(생략 시 횡단) |
{
"success": true,
"data": [
{
"site_code": "humanoid",
"slug": "robot-engineer",
"name": "ロボットエンジニア",
"parent_slug": null,
"description": null,
"job_count": 1
}
]
}
키워드·카테고리·도도부현·고용형태·원격·급여로 채용을 필터 검색.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai(생략 시 횡단) | |
keyword |
string |
직종명·스킬·기업명 | |
category_slug |
string |
카테고리 슬러그 | |
prefecture |
string |
도도부현명(예: 도쿄도) | |
employment_type |
string |
full_time / part_time / contract / freelance / internship | |
is_remote |
boolean |
원격 가능만 true | |
salary_min |
number |
최저 급여(만 엔) | |
limit |
number |
반환 건수(default 20, max 100) | |
offset |
number |
오프셋(페이지네이션) |
{
"success": true,
"data": {
"total": 11,
"limit": 20,
"offset": 0,
"results": [
{
"id": 1,
"site_code": "humanoid",
"slug": "sample",
"title": "ヒューマノイドロボットエンジニア",
"employment_type": "full_time",
"prefecture": "東京都",
"is_remote": 0,
"salary_min": 6000000,
"salary_max": 12000000,
"company_name": "Sample Robotics"
}
]
}
}
채용 상세 정보 취득(스킬 요건·복리후생·기업 정보).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
채용 ID(id 또는 slug 필수) | |
slug |
string |
채용 슬러그 | |
site_code |
string |
slug 지정 시 대상 사이트 |
{
"success": true,
"data": {
"id": 1,
"title": "ヒューマノイドロボットエンジニア",
"description": "...",
"skills_required": [
"ROS2",
"C++",
"Python"
],
"company_name": "Sample Robotics",
"industry": "ロボティクス"
}
}
신착 또는 주목 채용 목록(상단 페이지·위젯용).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai | |
featured_only |
boolean |
주목 채용만 true | |
limit |
number |
반환 건수 |
{
"success": true,
"data": [
{
"id": 1,
"title": "求人例",
"is_featured": 1,
"company_name": "Sample Robotics"
}
]
}
키워드·업종으로 기업을 필터 검색(활성 채용 수 포함).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai | |
keyword |
string |
기업명·설명 키워드 | |
industry |
string |
업종(예: 로보틱스) | |
limit |
number |
반환 건수(default 20, max 50) |
{
"success": true,
"data": [
{
"id": 1,
"company_name": "Sample Robotics",
"industry": "ロボティクス",
"active_job_count": 3
}
]
}
기업 상세 정보(기술 스택·오피스 이미지·활성 채용 목록).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
기업 ID(id 또는 slug 필수) | |
slug |
string |
기업 공개 슬러그 | |
site_code |
string |
slug 지정 시 대상 사이트 |
{
"success": true,
"data": {
"id": 1,
"company_name": "Sample Robotics",
"tech_stack": [
"ROS2",
"Python"
],
"active_jobs": [
{
"id": 1,
"title": "エンジニア"
}
]
}
}
채용 관련 기사를 키워드·카테고리로 검색.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai | |
keyword |
string |
제목·본문 키워드 | |
category |
string |
기사 카테고리 | |
limit |
number |
반환 건수 |
{
"success": true,
"data": [
{
"id": 1,
"title": "業界の最新トレンド",
"category": "trend",
"view_count": 1234
}
]
}
기사 본문을 포함한 상세 정보 취득.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
slug |
string |
YES | 기사 슬러그 |
site_code |
string |
대상 사이트 |
{
"success": true,
"data": {
"slug": "example",
"title": "記事タイトル",
"body": "記事本文..."
}
}
사이트별 통계 정보(활성 채용 수·기업 수·구직자 수·지원 수·기사 수).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai |
{
"success": true,
"data": [
{
"site_code": "humanoid",
"active_jobs": 1,
"companies": 1,
"seekers": 0,
"applications": 0,
"articles": 0
}
]
}
기업용 게재 플랜 목록(플랜명·월액·채용 슬롯·스카우트 슬롯·기능).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai |
{
"success": true,
"data": [
{
"slug": "basic",
"name": "ベーシック",
"price_monthly": 30000,
"job_limit": 3
}
]
}
【API 키 필요】API 키에 연결된 사용자 정보를 반환. 연결 확인에 사용.
파라미터 불필요.
응답 예시{
"success": true,
"data": {
"user_id": 2,
"email": "company@example.com",
"name": "テスト株式会社",
"role": "company"
}
}
【API 키 / 기업】자사가 게재 중인 채용 목록(draft 포함)을 반환.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
status |
string |
draft / active / closed / paused | |
limit |
number |
반환 건수(default 30, max 100) |
{
"success": true,
"data": [
{
"id": 1,
"title": "求人",
"status": "active",
"view_count": 2
}
]
}
【API 키 / 기업】채용을 신규 작성(초안 상태로 저장). jobs_publish로 공개.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
title |
string |
YES | 채용 제목 |
category_slug |
string |
YES | 카테고리 슬러그 |
description |
string |
YES | 채용 설명 본문 |
employment_type |
string |
full_time / part_time / contract / internship / remote | |
location |
string |
근무지 | |
is_remote |
boolean |
원격 가능 | |
salary_min |
number |
최저 연봉(엔) | |
salary_max |
number |
최고 연봉(엔) | |
requirements |
string |
필수 요건 | |
preferred |
string |
우대 요건 | |
benefits |
string |
복리후생 |
{
"success": true,
"message": "求人を下書きとして作成しました",
"data": {
"id": 15,
"slug": "job-abc123",
"status": "draft"
}
}
【API 키 / 기업】자사 채용을 갱신(지정 필드만 덮어쓰기).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 갱신할 채용 ID |
title |
string |
제목 | |
salary_min |
number |
최저 연봉 | |
salary_max |
number |
최고 연봉 | |
description |
string |
본문 |
{
"success": true,
"message": "求人を更新しました",
"data": {
"id": 15
}
}
【API 키 / 기업】채용을 공개(draft → active).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 공개할 채용 ID |
{
"success": true,
"message": "求人を公開しました",
"data": {
"id": 15,
"status": "active"
}
}
【API 키 / 기업】채용을 종료(active → closed).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 종료할 채용 ID |
{
"success": true,
"message": "求人を終了しました",
"data": {
"id": 15,
"status": "closed"
}
}
【API 키 / 기업】자사 기업 프로필을 취득.
파라미터 불필요.
응답 예시{
"success": true,
"data": {
"id": 1,
"company_name": "テスト株式会社",
"industry": "ロボティクス",
"employee_count": "50-100",
"website_url": "https://example.com"
}
}
【API 키 / 기업】자사 기업 프로필을 갱신(미작성 시 신규 작성).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
company_name |
string |
회사명(신규 작성 시 필수) | |
company_name_kana |
string |
후리가나 | |
industry |
string |
업종 | |
employee_count |
string |
직원 수(예: 50-100) | |
founded_year |
number |
설립 연도 | |
website_url |
string |
공식 사이트 URL | |
logo_url |
string |
로고 URL | |
description |
string |
회사 설명 | |
address |
string |
주소 | |
phone |
string |
전화번호 | |
contact_person |
string |
담당자명 |
{
"success": true,
"message": "企業プロフィールを更新しました",
"data": {
"id": 1
}
}
【API 키 / 구직자】본인 구직자 프로필을 취득.
파라미터 불필요.
응답 예시{
"success": true,
"data": {
"id": 1,
"full_name": "テスト 太郎",
"prefecture": "東京都",
"experience_years": 5,
"desired_job_category": "robot-engineer",
"is_public": 1
}
}
【API 키 / 구직자】본인 프로필을 갱신(미작성 시 신규 작성).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
full_name |
string |
성명(신규 작성 시 필수) | |
full_name_kana |
string |
후리가나 | |
birth_year |
number |
출생 연도(서기) | |
gender |
string |
male / female / other / prefer_not | |
prefecture |
string |
거주 도도부현 | |
experience_years |
number |
경력 연수 | |
current_status |
string |
employed / unemployed / student / other | |
desired_job_category |
string |
희망 직종 카테고리 | |
desired_salary_min |
number |
희망 최저 급여(만 엔) | |
resume_url |
string |
이력서 URL | |
pr_text |
string |
자기 PR | |
is_public |
boolean |
기업에 공개 여부 |
{
"success": true,
"message": "求職者プロフィールを更新しました",
"data": {
"id": 1
}
}
【API 키】지원 목록. 기업 역할은 자사 채용에 대한 지원, 구직자 역할은 본인이 제출한 지원.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
limit |
number |
반환 건수(default 30, max 100) |
{
"success": true,
"data": [
{
"id": 1,
"job_id": 1,
"job_title": "エンジニア",
"applicant_name": "テスト太郎",
"status": "pending",
"created_at": "2026-05-01 10:00:00"
}
]
}
【API 키 / 기업】자사 채용에 대한 지원 상태를 갱신.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 지원 ID |
status |
string |
YES | pending / reviewing / accepted / rejected / withdrawn |
{
"success": true,
"message": "応募ステータスを更新しました",
"data": {
"id": 1,
"status": "accepted"
}
}
【API 키】이벤트 발생 시 POST로 통지하는 Webhook을 등록(최대 5개).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
url |
string |
YES | POST 통지 대상 URL(https:// 필수) |
events |
array |
YES | new_application / application_status_changed / new_scout / job_published / job_closed |
label |
string |
식별용 라벨 |
{
"success": true,
"message": "Webhookを登録しました",
"data": {
"id": 1,
"url": "https://example.com/webhook",
"events": [
"new_application"
],
"secret": "abc123..."
}
}
【API 키】등록된 Webhook 목록(호출 횟수·실패 횟수 포함).
파라미터 불필요.
응답 예시{
"success": true,
"data": [
{
"id": 1,
"url": "https://example.com/webhook",
"events": [
"new_application"
],
"total_calls": 12,
"total_failures": 0
}
]
}
【API 키】Webhook을 삭제.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | Webhook ID |
{
"success": true,
"message": "Webhookを削除しました",
"data": {
"id": 1
}
}
【API 키】본인 알림 목록과 미읽음 건수를 반환.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
unread_only |
boolean |
미읽음만 true | |
limit |
number |
반환 건수(default 30) |
{
"success": true,
"data": {
"unread_count": 3,
"items": [
{
"id": 1,
"type": "new_application",
"title": "新着応募がありました",
"is_read": 0
}
]
}
}
【API 키】알림을 읽음 처리(ID 배열 또는 "all").
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
ids |
mixed |
YES | ID 배열 [1,2,3] 또는 "all" |
{
"success": true,
"message": "全ての通知を既読にしました",
"data": {
"marked": "all"
}
}
【API 키 / 기업】채용을 일괄 작성(최대 50건, 각 draft 상태).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
jobs |
array |
YES | 채용 객체 배열. 각 요소는 jobs_create와 동일한 필드 |
{
"success": true,
"message": "全ての求人を作成しました",
"data": {
"created_count": 50,
"error_count": 0,
"created": [
{
"index": 0,
"id": 15,
"slug": "...",
"title": "..."
}
],
"errors": []
}
}
【API 키 / 기업】기존 채용을 복제(draft 상태).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 복제 원본 채용 ID |
title |
string |
새 채용의 제목 |
{
"success": true,
"message": "求人を複製しました",
"data": {
"id": 20,
"slug": "...",
"cloned_from": 15,
"status": "draft"
}
}
【API 키 / 기업】채용별 표시 수·지원 수·즐겨찾기 수·CVR.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
채용 ID(생략 시 전체 채용 집계) |
{
"success": true,
"data": {
"total_jobs": 5,
"total_views": 1234,
"total_applications": 42,
"overall_conversion": 3.41,
"jobs": [
{
"id": 1,
"title": "...",
"view_count": 500,
"application_count": 15,
"favorite_count": 23
}
]
}
}
【API 키 / 기업】지원자 정보를 플랫 구조로 반환(CSV 변환용).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
job_id |
number |
특정 채용으로 필터링 | |
status |
string |
pending / reviewing / accepted / rejected / withdrawn |
{
"success": true,
"data": {
"count": 1,
"applicants": [
{
"id": 1,
"job_title": "ROS2エンジニア",
"applicant_email": "...",
"full_name": "テスト 太郎",
"prefecture": "東京都",
"status": "pending"
}
]
}
}
【API 키】사이트 내 active 채용에서 급여 통계(중앙값·사분위)를 계산.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
category_slug |
string |
카테고리 슬러그 | |
prefecture |
string |
도도부현 | |
is_remote |
boolean |
원격 가능만 |
{
"success": true,
"data": {
"sample_size": 42,
"min": 3000000,
"max": 15000000,
"median": 7500000,
"p25": 5500000,
"p75": 10000000,
"avg": 7800000,
"unit": "円 / 年"
}
}
【API 키】지정 채용과 유사한 채용을 반환(스코어링).
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 기준 채용 ID |
limit |
number |
반환 건수(default 10, max 30) |
{
"success": true,
"data": {
"source_id": 15,
"results": [
{
"id": 18,
"title": "類似求人",
"similarity_score": 85,
"company_name": "Sample"
}
]
}
}
【API 키 / 기업】자사 채용을 10개 항목으로 채점. 등급 A-D와 개선 힌트를 반환.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number |
YES | 채점할 채용 ID |
{
"success": true,
"data": {
"job_id": 15,
"score": 72,
"grade": "B",
"checks": [
{
"name": "タイトル20文字以上",
"pass": true,
"weight": 10
}
],
"summary": "良好。改善するともっと応募が増えます"
}
}
기업별 채용 모멘텀 시계열(채용 active/new 건수 추이와 급증 플래그)을 증권 코드와 함께 반환. 상장기업은 ticker/거래소/국가 연결.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
site_code |
string |
humanoid / physicalai / prompters(생략 시 횡단) | |
ticker |
string |
증권 코드로 필터(예: TSLA, 7203) | |
company |
string |
기업명 키워드 부분 일치 | |
period |
string |
weekly(기본) / monthly | |
group_by |
string |
company(기본) / ticker=증권 단위 집계(사명 변형·복수 소스 통합, members[]에 내역) | |
limit |
number |
반환할 최근 기간 수(default 26, max 104) | |
public_only |
boolean |
상장기업(ticker 연결)만 true | |
min_delta_pct |
number |
급증 판정 전기 대비 임계 %(default 50) |
{
"success": true,
"data": {
"as_of": "2026-05-19",
"period": "weekly",
"count": 12,
"top_surging": [
{
"company": "Tesla, Inc.",
"ticker": "TSLA",
"exchange": "NASDAQ",
"country": "US",
"active_delta_pct": 120,
"latest_active": 11,
"latest_new": 6
}
],
"series": [
{
"company": "Tesla, Inc.",
"ticker": "TSLA",
"exchange": "NASDAQ",
"country": "US",
"is_public": true,
"relation": "pure_play",
"site_code": "humanoid",
"latest_active": 11,
"prev_active": 5,
"active_delta_pct": 120,
"latest_new": 6,
"surge": true,
"points": [
{
"period_end": "2026-05-12",
"active_jobs": 5,
"new_jobs": 2
},
{
"period_end": "2026-05-19",
"active_jobs": 11,
"new_jobs": 6
}
]
}
]
}
}
DoS·악용 방지를 위해 Nginx 계층(L4) + PHP 계층(L7) 2단으로 레이트 제한을 구현. 초과 시 HTTP 429 + Retry-After 헤더로 반환.
| 엔드포인트 | 제한 | Burst | 이유 |
|---|---|---|---|
/api/auth.php | 1 req/sec | 5 | 브루트포스 대책 |
/api/mcp.php | 5 req/sec | 20 | DoS 대책(IP 단위) |
| 구분 | 제한 | 식별자 |
|---|---|---|
| 미인증 Read | 60 req/min | IP 주소 |
| 인증 Read | 200 req/min | API 키 ID |
| Write | 30 req/min | API 키 ID |
# HTTP/2 429
# Retry-After: 32
{
"success": false,
"message": "레이트 제한 초과: write 는 1분당 30회까지입니다",
"retry_after_sec": 32
}
클라이언트는 Retry-After 헤더 초만큼 대기 후 재시도하세요.
프로덕션 운영에 필요한 보안 대책을 다층 방어로 구현하고 있습니다.
| 레이어 | 대책 | 내용 |
|---|---|---|
| L4 (Nginx) | IP 기반 레이트 제한 | PHP 도달 전 과잉 요청 폐기 |
| HTTP Headers | 보안 헤더 | HSTS / X-Content-Type-Options / Referrer-Policy / Permissions-Policy / CSP frame-ancestors |
| CORS | Origin 화이트리스트 | physicalai-jobs.com / physicalai-jobs.com / kyuujin.prompters.jp / asi.co.jp 만 허용 |
| L7 인증 | API 키 검증 | Bearer + 정규식 매치 + SHA-256 해시 대조(타이밍 공격 내성) |
| L7 레이트 제한 | API 키 / IP 단위 | Read/Write 별도 상한, 초과 시 429 + Retry-After |
| 역할 검증 | company / seeker 경계 | 역할 위반 403, 타인 리소스 접근 404 |
| SQL Injection | PDO Prepared Statement | 모든 쿼리 플레이스홀더 사용, LIMIT 등 동적 부분은 intval 캐스트 |
| SSRF 대책 | Webhook URL 검증 | localhost / 10.x / 192.168.x / 172.16-31.x / 169.254.x / link-local 거부 |
| 브루트포스 | 로그인 시도 추적 | email 5회 / IP 20회 실패 시 15분 잠금 |
| 세션 | 쿠키 강화 | HttpOnly / Secure / SameSite=Lax |
| 에러 정보 | 비노출 | 예외 상세는 error_log 에만, 클라이언트에는 범용 메시지 |
| 항목 | 값 |
|---|---|
| 형식 | jn_ + hex 48자 = 51자 |
| 엔트로피 | 192비트(24바이트 난수) |
| 저장 형식 | SHA-256 해시(평문 미저장) |
| 스코프 | 발급 사용자 본인의 리소스만 |
| 최대 보유 수 | 5개 / 사용자 |
| 폐기 | 즉시 가능 (/mypage/api-keys/) |
⚠️ 키가 유출됐을 가능성이 있으면 즉시 폐기하세요. 폐기 후 다음 요청부터 401 이 됩니다.
관리자는 다음 대시보드에서 실시간 모니터링 가능: /admin/security/
로그는 30일 보관(일일 cron으로 자동 정리).
보안 취약점을 발견하시면 security@physicalai-jobs.com 으로 연락 주세요. 공개 전 패치를 제공합니다.
에러 시 success: false 와 HTTP 상태 코드로 반환. 예외 상세는 클라이언트에 노출되지 않음(범용 메시지만).
{
"success": false,
"message": "slug or id is required"
}
| HTTP | 의미 | 원인 예 |
|---|---|---|
400 | Bad Request | 필수 파라미터 부족·부정한 값·부정 JSON·SSRF 대상 URL |
401 | Unauthorized | API 키 무효·만료·형식 부정 |
403 | Forbidden | 역할 위반(예: seeker가 company 전용 도구 호출) |
404 | Not Found | 지정 리소스 없음 또는 편집 권한 없음 |
405 | Method Not Allowed | GET 으로 접근(POST 만 허용) |
429 | Too Many Requests | 레이트 제한 초과·브루트포스 잠금 중(Retry-After 참조) |
500 | Server Error | 내부 에러(상세는 error_log 에만) |