Source: https://docs.theseeker.io/index.md
# theseeker CRM 문서
> API 모니터링, 서버, 애널리틱스와 문서 사이트를 시작하는 안내서입니다.
theseeker CRM의 제품 가이드와 API 레퍼런스를 찾을 수 있습니다. 먼저 시작 안내를 읽거나 필요한 기능으로 이동하세요.
조직을 만들고 프로젝트와 API 키를 설정합니다.
가용성 검사와 상태 페이지를 구성합니다.
서버 에이전트로 호스트 상태와 알림을 관리합니다.
제품 사용 현황과 오류를 분석합니다.
조직 문서를 작성하고 릴리스로 게시합니다.
REST API, MCP와 SDK 계약을 확인합니다.
AI 코딩 에이전트는 [LLM 안내](/llm/overview)와 각 페이지의 Markdown 주소를 이용할 수 있습니다.
---
Source: https://docs.theseeker.io/getting-started/overview.md
# 시작하기
> 조직과 프로젝트를 만들고 첫 API 모니터를 등록하는 기본 흐름입니다.
## 기본 흐름
theseeker CRM의 모니터링 데이터는 조직 안의 프로젝트에 속합니다.
먼저 조직을 선택하고 프로젝트를 만든 다음 모니터와 키를 설정합니다.
1. [crm.theseeker.io](https://crm.theseeker.io)에 로그인합니다.
2. 조직을 선택하거나 새 조직을 만듭니다.
3. 프로젝트를 생성합니다.
4. 모니터를 추가하고 체크 주기를 정합니다.
5. 프로젝트 키 또는 관리 API 키를 발급합니다.
6. API, SDK, 또는 서버 에이전트에서 키를 사용합니다.
## 첫 모니터 만들기
모니터에는 프로젝트 안에서 유일한 `slug`와 표시 이름이 필요합니다.
모니터 이벤트를 보낼 때는 프로젝트 키를 사용하고, 관리 API를 호출할 때는 관리 API 키를 사용합니다.
```text
프로젝트
└── 모니터 slug
└── 상태 이벤트
```
체크 주기는 모니터의 예상 이벤트 간격을 의미합니다. 이벤트가 늦어지면 설정한 상태 전환 규칙에 따라 상태가 바뀝니다.
## 어떤 키를 사용할까요?
| 작업 | 권장 키 | 권한 예시 |
| --- | --- | --- |
| 상태 이벤트 전송 | 프로젝트 키 | `status:write` |
| 피드백 전송 | 프로젝트 키 | `feedback:write` |
| 프로젝트와 모니터 관리 | 관리 API 키 | `admin:write` |
| 서버 목록 조회 | 프로젝트 또는 조직 키 | `servers:read` |
## 다음 단계
키의 종류와 보안 규칙은 [API 키](/getting-started/api-keys)에서 확인하세요.
서버를 연결하려면 [서버 모니터링 개요](/server-monitoring/overview)를 읽으세요.
---
Source: https://docs.theseeker.io/getting-started/organizations-and-projects.md
# 조직과 프로젝트
> 조직 범위와 프로젝트 범위를 구분하고 리소스를 배치하는 방법입니다.
## 조직
조직은 팀과 프로젝트를 묶는 최상위 범위입니다. 관리 API 키는 기본적으로 조직에 속하며, 조직 안의 프로젝트를 조회하고 관리할 수 있습니다.
조직 슬러그는 앱 URL과 UI 경로에서 사용됩니다.
## 프로젝트
프로젝트는 모니터, 이벤트, 피드백, 서버를 묶는 작업 단위입니다. 프로젝트에는 사람이 읽는 이름과 API에서 사용하는 고유 `slug`가 있습니다.
| 속성 | 설명 |
| --- | --- |
| `name` | 화면에 표시할 프로젝트 이름 |
| `slug` | API query와 이벤트에서 사용하는 식별자 |
| 조직 | 프로젝트가 속한 조직 |
| 모니터 | 프로젝트의 상태 이벤트 대상 |
| 서버 | 프로젝트에 연결된 서버 에이전트 대상 |
## 프로젝트 선택
UI에서 프로젝트를 만들 때 이름과 슬러그를 함께 정합니다. REST API에서는 `POST /api/v1/projects`를 사용합니다.
```bash
curl -X POST https://crm.theseeker.io/api/v1/projects \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"slug":"payments","name":"Payments"}'
```
프로젝트 슬러그는 같은 조직에서 중복될 수 없습니다. 모니터와 서버를 등록할 때는 같은 프로젝트 슬러그를 지정해야 합니다.
## 권한 범위
프로젝트 키는 발급된 프로젝트에 고정됩니다. 조직 키는 조직 전체 프로젝트에 접근합니다.
프로젝트 키로 다른 프로젝트를 지정하면 API가 `403 project_forbidden`을 반환합니다.
서버를 만들기 전에 프로젝트를 하나 이상 만들어야 하며, 프로젝트가 없으면 서버 설정 화면의 서버 추가 버튼이 비활성화됩니다.
---
Source: https://docs.theseeker.io/getting-started/api-keys.md
# API 키
> 프로젝트 키와 관리 API 키의 차이, scope, IP 제한, secret 보관 방법을 설명합니다.
## 키 종류
| 종류 | 범위 | 주요 용도 |
| --- | --- | --- |
| 프로젝트 키 | 하나의 프로젝트 | 이벤트와 피드백 ingest, 프로젝트 서버 |
| 관리 API 키 | 조직 전체 | Projects, Monitors, Status Page, Feedback, Servers REST API |
프로젝트 키는 ingest 계열이고 `project_id`로 프로젝트에 연결됩니다. 관리 API 키는 조직 계열이며 조직 전체를 대상으로 합니다.
## Scope
| Scope | 한국어 표시 | 용도 |
| --- | --- | --- |
| `status:read` | 상태 읽기 | 상태 데이터 조회 |
| `status:write` | 상태 쓰기 | 상태 이벤트 전송 |
| `feedback:read` | 피드백 읽기 | 피드백 조회 |
| `feedback:write` | 피드백 쓰기 | 피드백 전송 |
| `analytics:write` | Analytics 쓰기(레거시) | 레거시 분석 이벤트 |
| `errors:write` | 에러 쓰기 | 서버 에러 수집·소스맵 업로드 |
| `admin:read` | 관리 읽기 | 관리 리소스 조회 |
| `admin:write` | 관리 쓰기 | 관리 리소스 변경 |
| `servers:read` | 서버 읽기 | 서버 목록과 상세 조회 |
| `servers:write` | 서버 쓰기 | 서버 등록, 수정, 삭제, 토큰 재발급 |
| `docs:read` | 문서 읽기 | 문서 사이트와 페이지 조회 |
| `docs:write` | 문서 쓰기 | 문서 사이트 작성과 게시 |
필요한 최소 scope만 선택하세요. `admin:read`와 `admin:write`는 서버 API에서도 각각 읽기와 쓰기 권한을 부여합니다.
문서 사이트 API와 MCP는 조직 키 전용입니다. `docs:read`와 `docs:write`는 `admin:read`와 `admin:write`로도 사용할 수 있습니다.
`errors:write`는 새 프로젝트 키에 적용됩니다. 기존 키에는 자동으로 추가되지 않으므로 새 키를 발급하거나, scope 편집이 활성화된 경우 키를 편집하세요.
## 발급과 secret
secret은 발급 직후 한 번만 표시됩니다. 안전한 secret manager나 mode-600 파일에 저장하고 로그, 저장소, 채팅에 출력하지 마세요.
키를 잃어버리면 기존 secret을 다시 조회할 수 없으므로 새 키를 발급해야 합니다.
## Bearer 형식
관리 API 요청은 다음 형식의 헤더를 사용합니다.
```http
Authorization: Bearer .
```
MCP 클라이언트(opencode·Claude Code 등)에서도 같은 키를 사용합니다. 설정 방법은 [MCP](/api-reference/mcp)를 참고하세요.
## IP allowlist와 폐기
키마다 CIDR 형식의 IP allowlist를 설정할 수 있습니다. 허용 목록 밖의 요청은 `403 ip_not_allowed`입니다.
사용하지 않는 키는 API 키 화면에서 폐기하세요. 폐기한 키는 즉시 인증에 실패합니다.
---
Source: https://docs.theseeker.io/api-monitoring/monitors.md
# 모니터
> API 상태 이벤트를 받을 모니터를 생성하고 조회하는 방법입니다.
## 모니터란?
모니터는 하나의 API나 작업의 상태를 나타내는 프로젝트 리소스입니다. 이벤트는 모니터 `slug`를 기준으로 연결됩니다.
결과는 `ok`, `degraded`, `down`, `error` 같은 상태로 표현할 수 있습니다.
## REST로 모니터 만들기
관리 API 키의 `admin:write` scope가 필요합니다.
```bash
curl -X POST https://crm.theseeker.io/api/v1/monitors \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectSlug":"payments",
"slug":"checkout-api",
"name":"Checkout API",
"intervalSec":60,
"degradedAfter":120,
"downAfter":240
}'
```
응답은 `201`이며 `monitor` 객체를 담습니다. 같은 프로젝트에서 `slug`는 중복될 수 없습니다.
## 목록과 변경
목록 조회에는 `admin:read` 또는 모니터 상태를 읽을 수 있는 키가 필요합니다.
```bash
curl "https://crm.theseeker.io/api/v1/monitors?projectSlug=payments" \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
모니터의 이름, 주기, 상태 전환 설정은 UI 또는 관리 API에서 관리합니다. 이벤트를 보낼 때는 프로젝트 키와 모니터 slug를 사용하세요.
## 운영 팁
`intervalSec`는 정상 이벤트가 도착해야 하는 예상 간격입니다. 외부 서비스의 실제 SLA보다 너무 짧게 설정하면 일시적인 네트워크 지연이 장애로 보일 수 있습니다.
---
Source: https://docs.theseeker.io/api-monitoring/status-page.md
# 상태 페이지
> 모니터 상태를 공개 페이지와 커스텀 도메인으로 제공하는 방법입니다.
## 공개 상태 페이지
상태 페이지는 프로젝트 모니터의 현재 상태를 외부 사용자에게 보여주는 공개 화면입니다.
조직 관리자는 상태 페이지를 활성화하고 `slug`, 제목, 설명, 컴포넌트를 설정합니다.
기본 공개 URL은 다음 형태입니다.
```text
https://crm.theseeker.io/status/
```
`slug`를 바꾸면 이전 URL은 redirect 없이 `404`가 됩니다. 링크를 배포하기 전에 변경 여부를 확인하세요.
## 커스텀 도메인
`customDomain`을 저장한 뒤 DNS에 CRM 앱을 가리키는 CNAME을 추가합니다.
```dns
status.example.com. CNAME crm.theseeker.io.
```
Cloudflare를 쓴다면 Proxied 상태를 권장합니다. UI의 연결 확인은 `dns_missing`, `dns_mismatch`, `dns_ok_tls_pending`, `active` 상태를 보여줍니다.
`active`는 라우팅 응답이 확인됐다는 뜻이며 도메인 소유권 증명은 아닙니다.
## API로 설정하기
관리 API 키가 필요합니다.
```bash
curl -X PATCH https://crm.theseeker.io/api/v1/status-page \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true,"title":"Acme Status","customDomain":"status.example.com"}'
```
자세한 요청 필드는 [Status Page 레퍼런스](/api-reference/status-page)를 참고하세요.
---
Source: https://docs.theseeker.io/api-monitoring/status-sdk.md
# Status SDK
> Node와 TypeScript에서 상태 이벤트, 서버 오류, 소스맵 CLI와 상태 페이지를 다루는 SDK 사용법입니다.
## 설치
```bash
npm i @the-seeker/status-sdk
```
## 이벤트 전송
`createStatusClient`는 ingest endpoint와 프로젝트 키를 사용합니다. secret은 환경 변수로만 전달하세요.
```ts
import { createStatusClient } from "@the-seeker/status-sdk";
const status = createStatusClient({
keyId: process.env.STATUS_KEY_ID!,
secret: process.env.STATUS_SECRET!,
endpoint: "https://ingest.example.com/v1/events",
slug: "checkout-api",
});
await status.report({ result: "ok", latencyMs: 123 });
```
이벤트마다 `slug`를 덮어쓸 수도 있습니다. 기본 slug와 이벤트 slug가 모두 없으면 SDK가 오류를 발생시킵니다.
## 피드백 전송
```ts
await status.sendFeedback({
uid: "user-123",
content: "검색 결과가 느립니다.",
fields: { plan: "pro" },
});
```
## 상태 페이지 관리
`createStatusAdminClient`는 CRM 앱 origin과 관리 API 키를 사용합니다. ingest 클라이언트와 자격증명이 다릅니다.
```ts
const admin = createStatusAdminClient({
baseUrl: "https://crm.theseeker.io",
keyId: process.env.STATUS_ADMIN_KEY_ID!,
secret: process.env.STATUS_ADMIN_KEY_SECRET!,
});
const page = await admin.getStatusPage();
```
4xx는 `StatusAdminApiError`로 즉시 전달되고, 네트워크와 5xx 오류는 기본 재시도 정책을 따릅니다.
## 서버 오류 수집
`@the-seeker/status-sdk` 0.3.0부터 `createErrorClient`로 Node 프로세스의 오류를 수집할 수 있습니다. 프로젝트 키에는 `errors:write`가 필요합니다.
```ts
import { createErrorClient } from "@the-seeker/status-sdk";
const errors = createErrorClient({
keyId: process.env.CRM_KEY_ID!,
secret: process.env.CRM_KEY_SECRET!,
domain: "example.com", // 또는 propertyId, 둘 중 하나만 지정
release: "web-1.2.3",
environment: "production",
});
errors.setUser({ id: "user-123" });
errors.setTag("component", "checkout");
errors.addBreadcrumb({ category: "log", message: "checkout started" });
const result = await errors.captureException(new Error("checkout failed"));
await errors.captureMessage("checkout warning", "warning");
await errors.flush();
```
`captureException`과 `captureMessage`는 `{ ok, status, issueId, error }` 결과를 반환하며 기본적으로 전송 실패를 throw하지 않습니다. `onError`로 실패를 관찰할 수 있습니다. `installGlobalHandlers()`는 uncaught exception과 unhandled rejection을 `fatal`로 전송하고 flush한 뒤 오류를 출력하고 프로세스를 종료합니다. 각각 `onUncaughtException: "continue"`, `onUnhandledRejection: "continue"`로 동작을 바꿀 수 있으며 반환된 함수를 호출해 핸들러를 해제합니다.
Breadcrumb 버퍼는 최근 50건입니다. 이메일 주소, Bearer 자격증명, 12자리 이상 연속 숫자는 전송 전에 가립니다. 폼 입력 값은 breadcrumb에 기록하지 마세요.
Python SDK `theseeker-status`도 `create_error_client()`와 `ErrorClient`를 제공합니다. `install_excepthook()`은 기존 `sys.excepthook` 및 threading hook을 호출해 애플리케이션의 기본 오류 처리를 유지합니다. 상세 예제와 Django/FastAPI 적용은 [Python SDK README](https://github.com/theseeker/crm/tree/main/packages/status-sdk-py)를 참고하세요.
## Source Maps CLI
CLI는 `theseeker-sourcemaps upload|list|delete`를 제공합니다. `THESEEKER_API_KEY=keyId.secret` 또는 `--api-key`를 사용하고, 기본 endpoint는 `https://crm.theseeker.io`입니다. 업로드 기본 URL prefix는 `~/`입니다.
```bash
npx theseeker-sourcemaps upload --release web-1.2.3 --domain example.com \
--url-prefix https://example.com/_next/static/ .next/static
npx theseeker-sourcemaps list --domain example.com
npx theseeker-sourcemaps delete --release web-1.2.3 --domain example.com
```
`--property-id`는 `--domain` 대신 쓸 수 있습니다. `--url-prefix`는 끝에 `/`가 있는 HTTP(S) URL, `/path/` 또는 `~/path/`여야 합니다. CLI는 `node_modules`를 제외해 `.map` 파일을 재귀 탐색하고 최대 100개, 합계 25 MiB 단위로 업로드합니다. 파일당 한도는 15 MiB입니다. `--dry-run`은 업로드 경로 또는 실행할 API URL을 표시합니다. `--endpoint`로 CRM base URL을 바꿀 수 있습니다.
프로덕션 소스맵을 만들려면 Next.js 설정에 `productionBrowserSourceMaps: true`를 지정하세요. **업로드가 끝나면 공개 빌드 출력에서** **`.map`** **파일을 삭제하세요.** 소스맵에 원본 코드가 들어갈 수 있습니다. 한 릴리스는 최대 1,000개 파일, 프로퍼티는 압축 저장 기준 1 GiB까지 보관합니다. 세부 endpoint와 오류 코드는 [Source Maps API](/api-reference/sourcemaps)를 참고하세요.
---
Source: https://docs.theseeker.io/server-monitoring/overview.md
# 서버 모니터링 개요
> 읽기 전용 에이전트로 호스트, PM2, systemd, nginx 상태를 수집합니다.
## 구조
서버 모니터링은 서버에 설치하는 `@the-seeker/server-agent`, ingest gateway, CRM 화면으로 구성됩니다.
에이전트는 WebSocket으로 `wss://ingest.theseeker.io/agent/ws`에 연결합니다.
```text
server-agent → ingest gateway → CRM
WebSocket /agent/ws
```
에이전트는 읽기 전용입니다. 원격 명령 실행이나 파일 수정 기능은 제공하지 않습니다.
## 수집 범위
| 대상 | 수집 내용 |
| --- | --- |
| Host | CPU, memory, disk, load, network, uptime |
| PM2 | 프로세스 상태, CPU, memory, restart count (PM2 데몬 RPC 소켓 `$PM2_HOME/rpc.sock` 에서 읽음) |
| systemd | 지정한 unit의 상태와 journal 로그 source |
| nginx | 설정에서 발견한 server와 access/error 로그 source |
허용된 온디맨드 요청은 `logs.tail`, `service.status`, `pm2.describe`, `nginx.sources` 네 가지입니다.
로그 tail은 `100`, `200`, `500`줄만 요청할 수 있습니다.
## 상태
에이전트는 기본 15초마다 heartbeat를 보냅니다. 마지막 heartbeat 이후 90초가 지나면 서버는 `offline`입니다.
연결 직후에는 `unknown`일 수 있으며, heartbeat가 도착하면 `online`으로 바뀝니다.
## 시작 순서
1. CRM에서 프로젝트를 만듭니다.
2. 서버 설정 화면에서 서버를 등록하고 토큰을 복사합니다.
3. [에이전트 설치](/server-monitoring/agent-install)를 실행합니다.
4. 서버 상세 화면에서 차트와 수집 capability를 확인합니다.
---
Source: https://docs.theseeker.io/server-monitoring/agent-install.md
# 에이전트 설치
> Ubuntu, macOS, nvm 전용 호스트에 server-agent를 설치하고 상태를 확인합니다.
## 사전 조건
에이전트는 Node.js 20 이상이 필요합니다. CRM 서버 설정에서 서버를 등록하면 토큰과 endpoint가 포함된 설치 안내가 표시됩니다.
토큰은 발급 직후 한 번만 표시되므로 안전한 곳에 복사하세요.
## Ubuntu, systemd
```bash
# Ubuntu (Node.js 20+ 필요)
sudo npm i -g @the-seeker/server-agent@latest
sudo theseeker-agent install --token --endpoint --user $USER
# macOS
npm i -g @the-seeker/server-agent@latest
theseeker-agent install --token --endpoint
```
``에는 API 응답의 `agentEndpoint`, 기본값 `wss://ingest.theseeker.io/agent/ws`를 사용합니다.
Linux의 `install`은 root 권한이 필요합니다. root가 아니면 파일을 쓰지 않고 수동 명령을 출력한 뒤 exit code `2`를 반환합니다.
에이전트 프로세스 자체는 `sudo` 없이 서비스 사용자로 실행됩니다.
설치 상태는 Ubuntu에서 `sudo theseeker-agent status --user $USER`, macOS에서 `theseeker-agent status --user $USER`로 확인합니다.
macOS에서는 `sudo`를 붙이지 않습니다. LaunchAgent는 GUI 로그인 세션에 연결되며 부팅 전용 daemon이 아닙니다.
## nvm 전용 호스트
root PATH에 Node.js가 없다면 로그인 사용자로 먼저 패키지를 설치합니다.
```bash
npm i -g @the-seeker/server-agent@latest
sudo "$(command -v node)" "$(command -v theseeker-agent)" install --token --endpoint wss://ingest.theseeker.io/agent/ws --user $USER
```
생성되는 systemd `ExecStart`에는 절대 Node 경로가 포함됩니다.
## 로그 권한
nginx나 journald를 읽어야 하면 install 명령에 `--add-groups`를 추가합니다. 또는 사용자를 `adm`, `systemd-journal` 그룹에 넣은 뒤 서비스를 재시작합니다.
## PM2 감시 설정
`--user`에는 PM2 daemon을 소유한 사용자를 지정합니다. PM2 소유자는 `ps -eo user,cmd | grep "PM2 v"`로 확인할 수 있습니다. 서비스 사용자가 다르면 에이전트가 빈 PM2를 보거나 다른 PM2 인스턴스를 읽습니다.
`PM2_HOME` 환경 변수와 `--pm2-home` 옵션은 PM2 state가 있는 위치를 지정합니다. nvm 전용 호스트에서는 `@the-seeker/server-agent@0.1.1` 이상의 `install`이 실행 중인 node 바이너리의 bin 디렉터리를 systemd PATH 앞에 자동으로 기록합니다. unit에는 `Environment=PATH=:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`이 들어가므로 nvm으로 설치한 PM2를 별도로 PATH에 추가할 필요가 없습니다.
`@the-seeker/server-agent@0.2.0`부터 `pm2 jlist` 대신 `$PM2_HOME/rpc.sock` RPC로 수집하며, 소켓이 없으면 빈 목록, 권한 오류면 `permission_denied`, 그 밖의 오류일 때만 `jlist`로 폴백합니다. 예전 방식은 `PM2_COLLECTOR=jlist`로 강제할 수 있습니다.
## 문제 해결
### PM2 프로세스가 0개로 보임
서비스 사용자가 PM2 소유자인지 `ls -la $PM2_HOME/rpc.sock`과 `ps -eo user,cmd | grep "PM2 v"`로 확인합니다. `--user`는 PM2 데몬 소유자여야 하며, 설치할 때 지정한 `--pm2-home`이 실제 PM2 state와 `rpc.sock`이 있는 위치인지도 확인합니다.
### PM2 미설치로 표시됨
로그인 사용자로 `pm2 list`가 되는데 대시보드에 `PM2 미설치`가 표시되면 systemd PATH에서 nvm의 PM2 경로가 빠진 경우일 수 있습니다. `ExecStart`의 절대 Node 경로 때문에 에이전트는 실행되지만, sibling binary인 `pm2`를 찾지 못해 capability가 `not_installed`가 됩니다.
0.1.1 이상으로 업그레이드하고 같은 토큰으로 `install`을 다시 실행합니다. 기존 토큰은 `/etc/theseeker-agent/config.json`에 mode `600`으로 보관되어 있으며 `sudo`로 읽을 수 있습니다.
```bash
npm i -g @the-seeker/server-agent@latest
sudo "$(command -v node)" "$(command -v theseeker-agent)" install --token --endpoint wss://ingest.theseeker.io/agent/ws --user
sudo systemctl restart theseeker-agent
```
같은 토큰으로 다시 실행해도 0.1.1은 unit과 설정만 다시 쓰고 실행 중인 서비스를 재시작하지 않습니다(`enable --now`는 실행 중이면 no-op). 이어서 `sudo systemctl restart theseeker-agent`를 실행해야 하며, 0.1.2부터는 `install`이 자동으로 재시작합니다. 업그레이드하지 않는 경우에는 systemd drop-in으로 `PM2_BIN`을 지정한 뒤 재시작합니다.
```bash
sudo systemctl edit theseeker-agent
[Service]
Environment=PM2_BIN=/home//.nvm/versions/node//bin/pm2
```
```bash
sudo systemctl restart theseeker-agent
```
### 로그 열기가 permission\_denied
PM2 out/err 로그가 `~/.pm2/logs` 밖에 있어도 일반 파일이면 tail할 수 있습니다. 예를 들어 `/home/theseeker/tradingrecipe-consumer/logs/*.log`가 가능합니다. 로그 경로가 허용된 루트(`/var/log/nginx`, `/logs`, `~/.pm2/logs`) 밖을 가리키는 symlink이면 `permission_denied`가 반환됩니다.
---
Source: https://docs.theseeker.io/server-monitoring/ai-agent-setup.md
# AI 에이전트 설정
> AI 코딩 에이전트가 서버 등록과 읽기 전용 에이전트 설치를 수행하도록 안내하는 프롬프트입니다.
## 개요
아래 프롬프트를 AI 코딩 에이전트에 전달하면 프로젝트 서버 등록, 설치, 상태 확인 순서를 안내할 수 있습니다.
프롬프트 자체에는 API key나 server token 같은 secret이 없습니다. 에이전트는 `THESEEKER_API_KEY` 환경 변수에서 키를 읽고, 값이 없으면 키 파일 경로를 물어봐야 합니다.
## 프롬프트
```text
Read and follow: https://docs.theseeker.io/server-monitoring/ai-agent-setup.md
- API base URL: https://crm.theseeker.io/api/v1
- API 키: 환경 변수 THESEEKER_API_KEY 로 전달합니다. 설정돼 있지 않으면 키 파일 경로를 저에게 물어보세요. 키 값은 절대 출력하지 마세요.
- 프로젝트 slug:
- 서버 이름: (slug: )
- 대상 호스트: (Ubuntu/Debian, systemd)
1. 키 확인: `GET /api/v1/servers?projectSlug=` 를 `Authorization: Bearer $THESEEKER_API_KEY` 로 호출해 200 을 확인합니다. 401/403 이면 중단하고 저에게 알립니다.
2. 서버 등록: `POST /api/v1/servers` 에 `{"projectSlug":"","name":"","slug":""}` 를 보냅니다. 응답의 `token`(1회성, `sa_` 로 시작), `agentEndpoint`, `install` 스니펫을 사용합니다. 토큰은 메모리 또는 mode-600 임시 파일에만 둡니다.
3. 에이전트 설치(대상 호스트, Node.js 20+): `sudo npm i -g @the-seeker/server-agent@latest` 후 `sudo theseeker-agent install --token --endpoint --user $USER`. `node` 가 nvm 으로만 설치돼 `sudo npm` 이 실패하면, 로그인 사용자로 `npm i -g @the-seeker/server-agent@latest` 를 실행한 뒤 `sudo "$(command -v node)" "$(command -v theseeker-agent)" install --token --endpoint --user $USER` 를 실행합니다(systemd 유닛의 ExecStart 에 node 절대 경로가 포함됩니다). 사용자가 `adm`, `systemd-journal` 그룹에 없으면 `--add-groups` 를 붙입니다.
4. PM2 감시 확인: 대상 호스트에서 PM2 를 쓰면 `--user` 는 PM2 데몬 소유자(`ps -eo user,cmd | grep "PM2 v"`)여야 합니다. 설치 후 대시보드에 "PM2 미설치" 가 보이는데 `pm2 list` 는 되는 경우, node/pm2 가 nvm 에 있어 서비스 PATH 에서 보이지 않는 것입니다. `@the-seeker/server-agent@latest`(0.1.1 이상)로 올리고 같은 install 명령을 다시 실행하면 systemd 유닛에 `Environment=PATH=:…` 가 기록됩니다. 0.1.2 미만은 이어서 `sudo systemctl restart theseeker-agent` 를 실행합니다.
5. 검증: 호스트에서 `theseeker-agent status` 가 active 를 보고하고, `GET /api/v1/servers/` 가 60초 안에 `"state":"online"` 을 반환해야 합니다.
- API 키와 `sa_` 토큰을 출력·로그·커밋하지 않습니다. 토큰을 담았던 임시 파일은 삭제합니다.
- 호스트의 다른 설정을 변경하지 않습니다. 예상치 못한 오류(2xx 가 아닌 응답, 설치 실패, 서비스 비활성)가 나면 중단하고 저에게 알립니다.
보고: 서버 id, slug, state(online/offline), 호스트의 `theseeker-agent status` 출력, 그리고 지시와 달라진 점.
```
## 동작 흐름
1. 환경 변수의 키로 서버 목록을 조회해 인증과 프로젝트 범위를 확인합니다.
2. `POST /api/v1/servers`가 1회성 `sa_` 토큰과 설치 스니펫을 반환합니다.
3. 대상 호스트에 패키지를 설치하고 systemd 에이전트를 등록합니다.
4. PM2 소유자 사용자와 nvm PATH 를 확인해 PM2 감시가 켜졌는지 봅니다.
5. 로컬 상태와 REST 상세 응답에서 `online`을 확인합니다.
## 필요한 권한
프로젝트 키에는 `servers:write`가 필요합니다. 조직 키는 `servers:write` 또는 `admin:write`를 사용할 수 있습니다.
## 문제 해결
`401`은 Bearer 형식이나 secret을 확인하세요. `403`은 `servers:write`와 프로젝트 범위를 확인하세요.
`409`는 서버 slug가 이미 사용 중이라는 뜻입니다. `429`에서는 `Retry-After`만큼 기다립니다.
nvm 전용 호스트는 위 nvm 명령을 사용하고, 로그가 비어 있으면 `--add-groups`를 검토하세요.
설치 후 90초 동안 heartbeat가 없으면 `offline`으로 표시됩니다.
`PM2 미설치` 가 보이면 서비스 사용자가 PM2 소유자인지와 에이전트 버전(0.1.1 이상)을 확인하세요.
---
Source: https://docs.theseeker.io/server-monitoring/rest-api.md
# 서버 REST API 사용법
> curl로 서버를 등록하고 조회, 수정, 삭제, 토큰 재발급을 수행합니다.
## 기본 설정
API base URL은 `https://crm.theseeker.io/api/v1`입니다. 예시에서는 실제 키를 출력하지 않고 환경 변수에서 읽습니다.
```bash
export THESEEKER_API_KEY='.'
export BASE='https://crm.theseeker.io/api/v1'
```
모든 요청에 다음 헤더를 사용합니다.
```http
Authorization: Bearer $THESEEKER_API_KEY
```
## 서버 목록
`admin:read` 또는 `servers:read`가 필요합니다. 조직 키는 조직 전체를 조회하고, 프로젝트 키는 자신의 프로젝트만 조회합니다.
```bash
curl -sS "$BASE/servers?projectSlug=payments" \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
응답은 `{ "servers": [...] }` 형태입니다.
## 서버 등록
`admin:write` 또는 `servers:write`가 필요합니다.
```bash
curl -sS -X POST "$BASE/servers" \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"projectSlug":"payments","name":"Payments API","slug":"payments-api","intervalSec":15,"watchedServices":["nginx.service"],"nginxEnabled":true}'
```
`201` 응답에는 `server`, `token`, `agentEndpoint`, `install.ubuntu`, `install.macos`, `install.nvm`이 들어 있습니다. `token`은 다시 조회할 수 없습니다.
예시 응답의 `server`에는 `"state": "unknown"`이 포함됩니다. 상태 행은 첫 heartbeat에서 생성되므로 등록 직후에는 상태를 알 수 없습니다.
```json
{ "server": { "state": "unknown" }, "token": "", "agentEndpoint": "wss://", "install": { "ubuntu": "...", "macos": "...", "nvm": "..." } }
```
프로젝트 키는 `projectSlug`를 생략할 수 있고 자신의 프로젝트로 자동 지정됩니다. 다른 프로젝트를 지정하면 `403 project_forbidden`입니다.
## 상세와 변경
```bash
curl -sS "$BASE/servers/" \
-H "Authorization: Bearer $THESEEKER_API_KEY"
curl -sS -X PATCH "$BASE/servers/" \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"name":"Payments API primary","intervalSec":30}'
```
상세 `server`에는 `state`, `lastSeenAt`, `agentVersion`, 최신 metrics가 포함됩니다. `state`는 `unknown`, `online`, `offline` 중 하나입니다.
## 삭제와 토큰 재발급
```bash
curl -sS -X DELETE "$BASE/servers/" \
-H "Authorization: Bearer $THESEEKER_API_KEY"
curl -sS -X POST "$BASE/servers//rotate-token" \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
토큰 재발급은 이전 토큰을 즉시 무효화하고 새 토큰과 설치 스니펫을 반환합니다.
재발급 응답의 `server.state`는 현재 상태이며, 상태 행이 없다면 `unknown`입니다. 예를 들어 연결된 에이전트라면 다음과 같습니다.
```json
{ "server": { "state": "online" }, "token": "", "agentEndpoint": "wss://", "install": { "ubuntu": "...", "macos": "...", "nvm": "..." } }
```
---
Source: https://docs.theseeker.io/server-monitoring/alerts-and-retention.md
# 알림과 데이터 보존
> 서버 오프라인, 자원 사용량, PM2 재시작 알림과 시계열 보존 기간을 설명합니다.
## 알림 규칙
알림 threshold는 현재 고정 계약입니다. 별도 편집 API는 제공하지 않습니다.
| 조건 | Trigger | Resolve |
| --- | --- | --- |
| heartbeat 중단 | 마지막 heartbeat 후 90초 | heartbeat 수신 시 |
| CPU 사용량 | 90% 이상 5분 | 85% 미만 5분 |
| memory 사용량 | 90% 이상 5분 | 85% 미만 5분 |
| disk 사용량 | 90% 이상 5분 | 85% 미만 5분 |
| PM2 restart | 같은 process가 10분 안에 3회 이상 재시작 | 조건 해소 후 |
중복 이벤트는 event별 dedupe key로 줄입니다. 서버 상세 화면의 알림 배지에서 활성 알림 수를 확인할 수 있습니다.
## 보존 기간
| 데이터 | 보존 기간 |
| --- | ---: |
| raw `server_metric_sample` | 7일 |
| raw `server_process_sample` | 3일 |
| 5분 `server_metric_5m` rollup | 90일 |
| 5분 `server_process_5m` rollup | 30일 |
raw hypertable은 1일 chunk를 사용하고 rollup은 5분 주기로 갱신합니다.
## 알림 해석
heartbeat가 기본 15초 간격이어도 네트워크나 호스트 중단을 90초까지 기다린 뒤 offline이 됩니다.
자원 알림은 순간적인 peak가 아니라 5분 지속 조건입니다. 상세 차트의 범위는 1시간, 6시간, 24시간, 7일을 제공합니다.
## 용량
gateway의 live connection 상한은 모든 조직을 합쳐 총 1,000개입니다. 조직별 용량 보장은 아니므로 대규모 연결이 필요하면 별도 용량 검토가 필요합니다.
## 점검 순서
알림이 예상과 다르면 먼저 서버의 `lastSeenAt`과 에이전트 상태를 확인하세요.
그 다음 해당 시각의 차트와 capability 상태를 함께 확인하면 수집 중단과 실제 자원 초과를 구분할 수 있습니다.
---
Source: https://docs.theseeker.io/analytics/overview.md
# 애널리틱스
> 웹 분석, Core Web Vitals, 퍼널, 공유 대시보드와 주간 리포트를 살펴보는 방법입니다.
## 개요
애널리틱스는 프로젝트에서 수집한 이벤트와 피드백을 운영 관점에서 확인하는 영역입니다.
모니터 상태는 API 모니터링 화면에서, 서버 자원 시계열은 서버 상세 화면에서 확인합니다.
## 데이터 흐름
```text
애플리케이션 또는 SDK
↓
프로젝트 키로 이벤트 전송
↓
프로젝트 분석 화면
```
이벤트를 보낼 때는 프로젝트 키를 사용하고, 조직 전체 관리 API를 호출할 때는 관리 API 키를 사용합니다.
키의 scope는 필요한 작업에 맞춰 최소 범위로 발급하세요.
## 확인할 항목
| 항목 | 확인 위치 |
| --- | --- |
| API 응답 상태 | 모니터 상태와 이벤트 |
| 지연 시간 | 이벤트의 `latencyMs` |
| 사용자 의견 | 피드백 목록 |
| 호스트 자원 | 서버 상세의 CPU, memory, disk, network |
## 운영 팁
모니터의 `slug`는 이벤트와 연결되는 안정적인 식별자이므로 임의로 바꾸지 않는 것이 좋습니다.
데이터 전송 실패 시 SDK의 오류 로그에 secret을 포함하지 않도록 환경 변수 구성을 점검하세요.
피드백을 자동 수집할 때는 사용자 식별자와 함께 민감한 본문을 무분별하게 보내지 말고, 프로젝트의 데이터 보존 정책을 따르세요.
## Web Vitals
추적 스크립트에 `data-capture-vitals` 속성을 추가하면 페이지가 숨겨지거나 종료될 때 지원되는 Core Web Vitals를 `/api/event`로 보냅니다.
```html
```
지원하는 지표는 LCP, INP, CLS, FCP, TTFB입니다. 브라우저가 제공한 지표만 전송하며 한 번의 beacon에 지표가 하나 이상 있어야 저장됩니다. 값은 ms 단위이고 CLS는 소수점 네 자리까지 집계됩니다.
| 지표 | 좋음 | 개선 필요 | 나쁨 |
| --- | ---: | ---: | ---: |
| LCP | ≤ 2,500 ms | ≤ 4,000 ms | \> 4,000 ms |
| INP | ≤ 200 ms | ≤ 500 ms | \> 500 ms |
| CLS | ≤ 0.1 | ≤ 0.25 | \> 0.25 |
| FCP | ≤ 1,800 ms | ≤ 3,000 ms | \> 3,000 ms |
| TTFB | ≤ 800 ms | ≤ 1,800 ms | \> 1,800 ms |
화면은 기간별 p75와 평가, 경로별 결과를 제공하며 전체·모바일·데스크톱 기기로 나눠 볼 수 있습니다. Web Vitals 원시 이벤트는 90일 보관합니다.
## 퍼널
프로퍼티별 퍼널은 이름과 2~8단계로 구성됩니다. 단계는 경로 glob을 사용하는 pageview 또는 이벤트 이름입니다. 예를 들어 `/pricing` 페이지뷰, `/signup` 페이지뷰, `signup_completed` 이벤트를 순서대로 설정하면 단계별 세션, 시작 대비·이전 단계 대비 전환율, 이탈 수를 확인할 수 있습니다. 단계는 같은 세션에서 앞 단계 이후 발생해야 합니다. 퍼널 이름은 프로퍼티 안에서 고유해야 합니다.
## 필터(드릴다운)
개요의 소스·페이지·진입 페이지·종료 페이지·국가·기기·브라우저·운영체제·채널·UTM 브레이크다운 행을 선택하면 해당 값이 필터로 추가됩니다. 필터는 URL에 저장되어 링크 공유와 새로고침 후에도 유지되고, 뒤로·앞으로 이동으로 이전 선택을 되돌릴 수 있습니다. 같은 차원에서는 한 값만 적용되며 새 값을 고르면 기존 값이 바뀝니다. 서로 다른 차원의 필터는 AND로 결합됩니다.
필터가 활성화되면 개요 지표는 선택한 기간에 시작한 세션 중 모든 세션 조건에 맞는 범위를 기준으로 계산합니다. 페이지 필터는 그 세션에서 선택한 경로의 pageview가 기간 안에 발생했는지도 확인합니다. 방문자는 해당 세션의 고유 사용자, 방문은 세션 수, 페이지뷰는 해당 세션의 기간 내 pageview 수입니다. 리드와 매출도 같은 세션에 속한 이벤트만 집계합니다. 필터가 있는 동안 Clicks는 지원되지 않아 대시보드에 `—`로 표시됩니다.
브레이크다운의 소스·국가·기기·브라우저·운영체제·페이지 수치는 페이지뷰 수이고, 채널·진입 페이지·종료 페이지·UTM 수치는 세션 수입니다. 필터 조건은 서로 AND로 연결됩니다.
## 사이트 전환
애널리틱스 화면의 사이트 선택기에서 프로퍼티를 바꾸면 선택한 사이트의 데이터를 확인할 수 있습니다. 선택은 화면 이동 중에도 유지됩니다. 단축 링크 화면에서는 특정 사이트가 아니라 `전체 사이트`를 선택할 수도 있습니다.
## 기간 선택
개요·성능·퍼널에서는 `오늘`, `7일`, `30일`, `90일` 프리셋이나 `사용자 지정` 기간을 선택할 수 있습니다. 오늘은 조직 시간대의 자정부터 현재까지이며, 날짜 범위는 조직 시간대 기준 시작일과 종료일을 모두 포함합니다. 사용자 지정 기간은 최근 90일 범위 안에서 최대 90일까지 선택할 수 있습니다. 보존 기간을 넘기거나 미래 날짜를 선택할 수 없습니다. 에러 화면의 기간은 오류 발생 시각을 거르는 필터이며, 세션과 실시간은 실시간 창을 사용합니다. 링크 통계는 링크별 고정 기간을 사용합니다.
## 이전 기간 비교와 CSV
개요에서 이전 기간 비교를 켜면 현재 기간과 직전 동일 길이 기간을 함께 확인합니다. CSV는 화면 다운로드 또는 `GET /api/analytics/export`로 내보낼 수 있습니다. 사용자 지정 기간은 `from`과 `to` ISO 날짜로 전달하며 기간은 최대 90일입니다. 필터가 활성화된 동안에는 CSV 내보내기가 비활성화됩니다. 내보내려면 먼저 필터를 지우세요.
`report`는 `timeseries`, `sources`, `channels`, `utm_sources`, `utm_mediums`, `utm_campaigns`, `top_pages`, `entry_pages`, `exit_pages`, `countries`, `devices`, `browsers`, `os`, `goals`, `vitals_summary`, `vitals_pages`, `vitals_daily`, `funnel`을 지원합니다. Vitals 보고서에는 `device=all|mobile|desktop`, 퍼널 보고서에는 `funnelId`를 지정합니다. 결과는 UTF-8 BOM과 RFC 4180 CRLF를 쓰며 `Cache-Control: no-store`로 제공됩니다. `=`, `+`, `-`, `@`, 탭 또는 CR로 시작하는 문자열에는 CSV 수식 실행을 막기 위한 작은따옴표가 붙습니다. 요청은 사용자당 분당 30회로 제한됩니다.
## 공유 대시보드
관리자는 프로퍼티 하나에 공개 공유 링크를 만들고 폐기할 수 있습니다. 링크는 capability URL이므로 수신자에게만 전달하세요. 공개 화면은 지표, 기간 비교, 시계열, breakdown, 목표와 Web Vitals 요약만 표시합니다. 실시간 방문자, 세션, 오류, 링크 관리 정보와 다른 프로퍼티는 공개하지 않습니다. 폐기한 링크는 즉시 사용할 수 없고, 링크 페이지는 검색 색인과 referrer 전달을 제한합니다.
## 주간 이메일 리포트
각 사용자는 프로퍼티별 주간 리포트를 설정할 수 있고, 설정 화면에서 자신에게 테스트 메일을 보낼 수 있습니다. 리포트는 조직 시간대 기준 월요일 09:00 이후에 지난 월요일부터 일요일까지의 한 주를 발송 대상으로 삼습니다. 매주 한 번 발송되며 실패한 발송은 최대 3회까지 재시도합니다.
## 관련 문서
상태 이벤트 전송은 [Status SDK](/api-monitoring/status-sdk)를, 서버 자원 확인은 [서버 모니터링 개요](/server-monitoring/overview)를 참고하세요.
에러 수집은 [에러 트래킹](/analytics/errors), 위젯과 설문은 [피드백](/feedback/overview)을 참고하세요.
---
Source: https://docs.theseeker.io/analytics/realtime.md
# 실시간 애널리틱스
> 현재 방문자와 최근 활동을 실시간 화면에서 확인합니다.
## 실시간 화면
애널리틱스의 실시간 화면에서는 선택한 사이트의 현재 방문자와 최근 활동을 확인할 수 있습니다. 현재 방문자는 최근 5분 동안 활동한 고유 사용자 수입니다. 분당 방문자 그래프는 최근 30분을 1분 단위로 나누며, 방문이 없던 분도 0으로 표시해 항상 30개 막대를 보여 줍니다.
라이브 스트림에는 최근 활동이 표시됩니다. 경로, 유입 소스, 국가, 기기 등 수집된 이벤트 정보를 확인할 수 있습니다. 화면의 요약 목록에는 최근 5분의 상위 페이지, 소스, 국가가 표시됩니다.
## 새로고침 제어
화면은 10초마다 자동으로 갱신됩니다. `일시정지`를 선택하면 갱신이 멈추고 `재개`를 선택하면 다시 시작합니다. 자동 갱신 스위치도 같은 일시정지 상태를 바꿉니다. 브라우저 탭이 숨겨져 있는 동안에는 자동 갱신을 중지하고, 탭으로 돌아오면 다시 갱신합니다.
## 사이트 전환
사이트 선택기에서 프로퍼티를 바꾸면 해당 사이트의 실시간 방문자, 그래프, 스트림을 확인할 수 있습니다. 선택한 사이트는 다른 애널리틱스 화면으로 이동해도 유지됩니다.
---
Source: https://docs.theseeker.io/analytics/errors.md
# 에러 트래킹
> 브라우저와 서버 오류 수집, 릴리스, 소스맵, 알림을 설정합니다.
## 브라우저 오류 수집
기존 analytics script 태그에 `data-capture-errors`를 추가하면 전역 오류와 처리되지 않은 Promise 거부를 수집합니다. 릴리스와 환경은 각각 `data-release`, `data-environment`로 전달합니다.
```html
```
릴리스는 최대 200자, 환경은 최대 64자입니다. 브라우저 tracker는 같은 오류를 60초 동안 중복 수집하지 않습니다. 브라우저 오류 이벤트에는 stack 최대 5,000자, message 최대 2,000자, type 최대 200자가 실립니다.
## Breadcrumbs와 개인정보
tracker는 최근 30개의 breadcrumb를 오류에 함께 보냅니다. 페이지 이동, 클릭, console `warn`/`error`, 실패한 fetch/XHR과 custom event를 기록합니다. Network breadcrumb는 URL query와 hash를 제거합니다. 입력 필드의 값은 수집하지 않습니다. 클릭 텍스트는 링크·버튼 등에서만 최대 40자 기록하고, `[data-feedback-mask]` 또는 contenteditable 내부는 제외합니다.
Breadcrumb 문자열에서 이메일 주소는 `[email]`, `Bearer` 자격증명은 `Bearer [redacted]`, 12자리 이상 연속 숫자는 `[number]`로 바뀝니다. 메시지는 최대 200자, data는 최대 10개 scalar 값입니다. 폼 입력값이나 query string에 민감한 정보를 넣지 마세요.
## 릴리스와 소스맵
배포마다 `data-release`에 빌드 릴리스를 지정하고 같은 릴리스 이름으로 소스맵을 업로드합니다. Next.js는 `productionBrowserSourceMaps: true`로 브라우저 소스맵을 생성할 수 있습니다. 업로드 후에는 공개 빌드 출력에서 반드시 `.map` 파일을 삭제하세요. 소스맵에 원본 코드가 포함될 수 있습니다.
```js
// next.config.mjs
export default { productionBrowserSourceMaps: true };
```
```bash
npx theseeker-sourcemaps upload --release web-1.2.3 --domain example.com \
--url-prefix https://example.com/_next/static/ .next/static
```
소스맵을 업로드하면 원본 위치와 문맥이 오류 프레임에 연결되고 fingerprint가 바뀌어 새 이슈가 한 번 만들어질 수 있습니다. 이후 같은 릴리스의 동일 오류는 해당 이슈에 쌓입니다. API로 목록, 릴리스별 파일 조회와 삭제를 할 수 있습니다. 자세한 multipart 필드, 한도, 응답은 [Source Maps API](/api-reference/sourcemaps)를 참고하세요.
## 재발과 영향 사용자
해결한 이슈가 이후 릴리스에서 다시 발생하면 재발 상태와 재발 횟수가 기록됩니다. 오류 화면에는 최근 30일의 영향을 받은 사용자 수가 표시됩니다. 사용자 ID가 없는 이벤트는 사용자 수에 포함되지 않습니다.
## 중요도 분류
오류 화면은 각 이슈를 제목(`<타입>: <메시지>`)과 수집 플랫폼으로 **높음 · 중간 · 낮음** 중 하나로 자동 분류합니다. 분류는 조회할 때 계산하므로 규칙이 바뀌면 과거 이슈에도 바로 적용되고, 이슈 묶음(fingerprint)과 알림은 바뀌지 않습니다.
| 중요도 | 의미 | 예시 |
| --- | --- | --- |
| 높음 | 아래 규칙에 해당하지 않는 앱 오류와 모든 Node·Python 서버 오류 | `TypeError: (0 , r.mf) is not a function` |
| 중간 | 하이드레이션·SSR 불일치, 구형 브라우저의 스크립트 파싱 오류 | `Error: Minified React error #418`, `SyntaxError: Unexpected token '{'` |
| 낮음 | 배포 전환 중 청크 로드 실패, 네트워크 끊김, 브라우저 확장·지갑·인앱 브라우저 주입 스크립트, 상세가 없는 외부 스크립트 오류, 브라우저 환경 제약 | `ChunkLoadError: Loading chunk 4219 failed.`, `TypeError: Load failed`, `Error: Script error.` |
목록은 기본으로 **높은 중요도** 이슈만 보여 줍니다. 툴바의 중요도 선택에서 중간·낮은 중요도나 전체 중요도를 고를 수 있고, 선택은 URL의 `importance` 파라미터(`medium`, `low`, `all`)로 공유됩니다. 이슈 행과 상세의 중요도 배지에서 분류 사유(예: `낮음 · 청크 로드 실패`)를 확인할 수 있습니다.
## 알림
프로퍼티별로 새 이슈, 재발, 오류 급증 알림을 각각 켜거나 끌 수 있습니다. 급증 기준은 10~100,000건이며 집계 구간은 5, 15, 30, 60, 180, 360 또는 1,440분 중 고릅니다. 기본값은 기준 100건, 60분입니다.
알림은 조직에 활성 private Telegram 구독이 있어야 발송됩니다. 구독자의 Telegram 설정에서 `에러` 알림을 켜세요. CRM 알림 센터에도 새 이슈·재발·급증 알림이 표시됩니다.
## 서버 오류 수집
Node SDK와 Python SDK 모두 프로젝트 키의 `errors:write` scope가 필요합니다. `domain` 또는 프로퍼티 ID 중 하나를 지정합니다. 서버 오류 API는 `/api/error/server`이며 HMAC 서명 요청을 사용합니다.
```ts
import { createErrorClient } from "@the-seeker/status-sdk";
const errors = createErrorClient({
keyId: process.env.CRM_KEY_ID!,
secret: process.env.CRM_KEY_SECRET!,
domain: "example.com",
release: "api-1.2.3",
environment: "production",
});
errors.setUser({ id: "user-123" });
errors.addBreadcrumb({ category: "log", message: "request started" });
await errors.captureException(new Error("request failed"));
```
Node의 `installGlobalHandlers()`는 uncaught exception과 unhandled rejection을 fatal로 수집하고 기본적으로 flush한 뒤 프로세스를 종료합니다. 옵션으로 각 핸들러의 `"continue"` 동작을 선택할 수 있습니다. Python의 `install_excepthook()`은 기존 `sys` 및 thread 예외 hook을 이어 호출합니다.
`errors:write`는 새 프로젝트 키에 추가되는 scope입니다. 기존 키에는 소급 적용되지 않으므로 새 프로젝트 키를 발급하세요. scope 편집이 활성화된 계정은 기존 키를 편집해 추가할 수 있습니다. [API 키 문서](/getting-started/api-keys)에서 scope를 확인하세요.
원시 오류 이벤트는 30일 보관합니다. SDK 설치와 전체 CLI 옵션은 [Status SDK](/api-monitoring/status-sdk), 업로드 endpoint는 [Source Maps API](/api-reference/sourcemaps)를 참고하세요.
---
Source: https://docs.theseeker.io/feedback/overview.md
# 피드백
> SDK 피드백, 임베드 위젯, 상태·태그, 오류 연결과 NPS·CSAT 설문을 설정합니다.
## 피드백 보내기
Status SDK의 `sendFeedback`을 사용하면 이벤트 endpoint와 연결된 프로젝트로 피드백을 보낼 수 있습니다.
```ts
await status.sendFeedback({
uid: "user-123",
content: "검색 결과가 느립니다.",
fields: { plan: "pro" },
extra: { screen: "search" },
});
```
`uid`는 애플리케이션이 사용하는 사용자 식별자이고 `content`는 사용자 의견입니다.
추가 분류 정보는 `fields`, 부가 문맥은 `extra`에 넣습니다.
## REST 조회
관리 API 키의 `admin:read` 또는 `feedback:read`가 필요합니다.
```bash
curl -sS https://crm.theseeker.io/api/v1/feedback \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
응답은 프로젝트와 조직 권한 범위에 따라 반환됩니다. 프로젝트 키는 자신이 연결된 프로젝트 밖의 데이터를 조회할 수 없습니다.
## 실패 처리
SDK는 기본적으로 실패 시 throw합니다. `throwOnError: false`를 선택하면 오류를 로그로 남기고 호출 흐름을 계속할 수 있습니다.
secret은 로그에 포함되지 않으며, 4xx 응답은 자동으로 무한 재시도하지 않습니다.
## 개인정보
피드백 본문에는 비밀번호, access token, 결제 정보 같은 secret을 넣지 마세요.
필요한 경우 서버에서 입력을 정제한 뒤 전송하세요.
## 임베드 위젯
프로젝트 설정에서 위젯을 활성화하고 허용 도메인을 등록한 다음 아래 스크립트를 페이지에 추가합니다. `data-key`에는 위젯의 공개 키를 넣습니다. `data-user-id`는 선택 사항이며 `TheSeekerFeedback.setUser()`로 실행 중 바꿀 수도 있습니다.
```html
```
페이지에서 `TheSeekerFeedback.open()`, `.close()`, `.setUser(id)`를 호출해 위젯을 제어할 수 있습니다. 위젯 설정의 허용 도메인과 일치하는 Origin에서만 config 조회와 제출이 허용됩니다. 설정은 `bottom-right` 또는 `bottom-left` 위치, 버튼 문구, accent 색상과 스크린샷 사용 여부를 가집니다.
스크린샷 첨부는 선택 사항이며 뷰포트 캡처를 JPEG로 압축해 한 장만 첨부합니다. 비밀번호 입력은 비우고 `[data-feedback-mask]`가 붙은 요소는 `••••`로 가립니다. 입력이나 표시 정보가 캡처되면 안 되는 DOM에 이 속성을 지정하세요.
제출 제한은 본문 1~5,000자, 연락 이메일 최대 254자, 사용자 ID 최대 128자입니다. 페이지 URL은 최대 2,000자입니다. 요청은 최대 2 MiB, 스크린샷은 JPEG 최대 1,572,864바이트입니다. IP와 위젯 키 조합당 10분에 10회, 키당 10분에 100회로 제한됩니다.
## 피드백 상태와 연결
대시보드에서 피드백 상태를 `new`, `in_progress`, `resolved`, `closed`로 관리하고 태그를 붙일 수 있습니다. 상세에는 세션과 연결된 오류 이슈가 표시될 수 있습니다. 위젯 데이터는 피드백으로, SDK 전송은 SDK 소스로 저장되며 항목에서 종류와 페이지 URL, 사용자 환경 정보를 확인합니다.
## NPS와 CSAT 설문
프로젝트당 활성 설문은 하나이며 NPS 또는 CSAT 유형을 선택합니다. 질문은 최대 200자, 후속 질문은 선택 사항이며 최대 200자입니다. 표시 지연은 0~~600초, 경로 패턴은~~ ~~`*`~~ ~~wildcard, 표본 비율은 0~~100%, 재표시 대기 기간은 1~365일입니다. 방문자 브라우저의 localStorage에 응답 또는 닫은 시점을 기록해 cooldown 동안 다시 표시하지 않습니다. localStorage를 쓸 수 없으면 설문을 표시하지 않습니다.
NPS 점수는 `round(100 × (추천자 수 - 비추천자 수) / 응답 수)`입니다. 추천자는 9~~10점, 중립은 7~~8점, 비추천자는 0~~6점입니다. CSAT 점수는 4~~5점 응답 비율을 백분율로 반올림합니다. 설문 응답은 Telegram 알림을 생성하지 않습니다.
위젯 제출 endpoint와 REST 조회 필드는 [Feedback API](/api-reference/feedback)를 참고하세요.
---
Source: https://docs.theseeker.io/docs-sites/overview.md
# 문서 사이트 개요
> 조직의 제품 문서를 작성하고 안전하게 공개하는 Docs 기능을 소개합니다.
## 문서를 한곳에서 관리하세요
Docs는 조직이 자체 제품 문서를 만들고 공개하는 CRM 기능입니다. 탭과 그룹으로 탐색 구조를 만들고, 페이지 초안을 편집한 뒤 불변 릴리스로 게시합니다. 공개, 비공개, 비공개 링크 방식의 노출 범위와 기본 주소, 커스텀 도메인을 설정할 수 있습니다.
자동 저장, 중첩 탐색, 미리보기와 컴포넌트 편집을 지원합니다.
MCP, REST API, SDK로 문서 초안을 관리하고 게시할 수 있습니다.
## 역할과 권한
| 작업 | 조직 소유자·관리자 | 편집 가능한 구성원 | 읽기 전용 구성원 |
| :--- | :---: | :---: | :---: |
| 사이트 생성·삭제 및 설정 변경 | 가능 | 불가 | 불가 |
| 초안·내비게이션 편집, 자산 업로드 | 가능 | 가능 | 불가 |
| 게시 및 릴리스 복원 | 가능 | 가능 | 불가 |
| 문서 열람 | 가능 | 가능 | 가능 |
## 사이트 생명주기
```mermaid
flowchart LR
A[사이트 생성] --> B[페이지와 내비게이션 편집]
B --> C[미리보기]
C --> D[릴리스 게시]
D --> E[공개 문서 사이트]
E --> F[초안 수정]
F --> D
```
게시된 릴리스는 변경되지 않습니다. 수정은 새 초안에 저장하고 다시 게시하세요.
다음 단계는 [에디터와 페이지 작성](/docs-sites/editor)과 [게시 및 공개 범위](/docs-sites/publishing)입니다.
---
Source: https://docs.theseeker.io/docs-sites/editor.md
# 에디터와 페이지 작성
> 문서 편집기, 자동 저장, 내비게이션과 충돌 해결 방법을 안내합니다.
## 페이지 편집
사이트 작업 공간에서 페이지를 선택하면 서식 도구 모음과 본문 편집기가 열립니다. 제목, 설명, URL 경로, 사이드바 이름, 아이콘, 숨김 여부를 조정할 수 있습니다. 페이지 경로는 사이트 안에서 고유해야 합니다.
삽입 메뉴에서 문단, 제목, 목록, 표, 코드와 문서 컴포넌트를 추가합니다. 선택한 텍스트에는 굵게, 기울임, 취소선, 밑줄, 강조, 링크와 툴팁을 적용할 수 있습니다. 텍스트 주변의 버블 메뉴는 선택 범위에 맞는 편집 명령을 제공합니다.
## 자동 저장과 충돌
편집 내용은 자동 저장되며 페이지마다 revision 번호가 올라갑니다. MCP나 SDK에서 같은 페이지를 동시에 바꾸고 revision이 달라지면 저장은 충돌로 거부됩니다. 최신 페이지를 다시 읽고 변경을 합친 뒤 저장하세요.
충돌 응답을 무시하고 기존 본문을 다시 보내면 다른 편집자의 내용을 덮어쓸 수 있습니다.
## 내비게이션 트리
사이드바 편집기에서 탭, 그룹, 페이지를 이동해 순서를 정합니다. 페이지를 다른 페이지 아래로 끌어 중첩 페이지를 만들 수 있습니다. 숨김 페이지와 그룹에 배치되지 않은 페이지는 URL로 접근할 수 있지만 목록 탐색에는 나타나지 않습니다.
경로와 제목을 정하고 페이지를 적절한 그룹에 배치합니다.
공개 사이트와 같은 레이아웃에서 내용과 탐색 구조를 살핍니다.
릴리스 메시지를 입력해 현재 초안을 고정된 릴리스로 만듭니다.
컴포넌트 입력 예시는 [컴포넌트 레퍼런스](/docs-sites/components)를 참고하세요.
---
Source: https://docs.theseeker.io/docs-sites/components.md
# 컴포넌트 레퍼런스
> 문서 작성에 사용할 수 있는 블록, 인라인 요소와 서식의 예시입니다.
이 페이지는 에디터에서 지원하는 콘텐츠 요소를 한눈에 보여줍니다. 링크와 강조 서식도 본문에서 바로 시험할 수 있습니다.
# 페이지 안의 큰 제목
## 기본 콘텐츠
일반 문단의 **굵은 글씨**, *기울임*, ~~취소선~~, `인라인 코드`, [링크](/getting-started/overview), 밑줄, 강조, H2O와 2nd 표기입니다. 도움말은 인라인 문맥을 보완합니다.\
줄 바꿈도 문단 안에서 지원합니다.
> 인용 블록은 다른 자료나 요약을 구분할 때 씁니다.
## 상태와 아이콘
참고 사항을 본문 흐름에서 분리합니다.
주의가 필요한 동작을 설명합니다.
추가 정보를 제공합니다.
작업을 더 빠르게 하는 방법입니다.
확인된 상태를 표시합니다.
주의하지 않으면 영향을 주는 작업입니다.
사용자 정의 아이콘과 색을 적용한 안내입니다.
회색 파랑 초록 노랑 주황 빨강 보라 흰색 표면 위험 강조 위험 표면
숫자 각주1와 화학식 H2O를 표현합니다.
### 제목과 목록
#### 중첩 항목
- 글머리 목록
- 하위 항목
- 추가 항목
1. 순서 목록
2. 다음 단계
- [x] 완료한 작업
- [ ] 남은 작업
---
### 표와 정렬
| 왼쪽 | 가운데 | 오른쪽 |
| :--- | :---: | ---: |
| 값 A | 값 B | 값 C |
### 코드 블록 옵션
```typescript title="예제.ts" icon="code" highlight="1-2" lines wrap expandable
const status = "online";
console.log(status);
```
```bash title="셸"
echo "ready"
```
## 안내 상자
참고 사항을 본문 흐름에서 분리합니다.
주의가 필요한 동작을 설명합니다.
추가 정보를 제공합니다.
작업을 더 빠르게 하는 방법입니다.
확인된 상태를 표시합니다.
주의하지 않으면 영향을 주는 작업입니다.
사용자 정의 아이콘과 색을 적용한 안내입니다.
## 카드와 열
링크와 아이콘을 가진 카드입니다.
가로 배치와 행동 라벨을 지정할 수 있습니다.
아코디언 안에도 문단을 넣을 수 있습니다.
접고 펼칠 수 있는 보충 콘텐츠입니다.
## 단계와 탭
단계 안에 일반 콘텐츠를 배치합니다.
초안 콘텐츠입니다.
게시 콘텐츠입니다.
## API 필드와 예시
반환할 항목 수입니다.
결과 목록을 반환합니다.
```bash title="요청"
curl https://crm.theseeker.io/api/v1/docs/sites
```
```json title="응답"
{"sites": []}
```
Docs API 레퍼런스
미리보기 콘텐츠
## 프롬프트와 타일
```text
먼저 현재 문서를 읽고, 확인된 동작만 수정하세요.
```
## 트리와 색상
검증됨
## 업데이트와 뷰
새 문서 사이트 기능을 사용할 수 있습니다.
요약 뷰에 표시되는 설명입니다.
상세 뷰는 서로 다른 독자를 위한 내용을 나눕니다.
이 내용은 에이전트용 Markdown에 포함됩니다.
## 이미지, 영상, 프레임과 수식
```mermaid
flowchart LR
draft[초안] --> release[릴리스]
```
블록 수식은 다음과 같이 표시합니다.
$$
E = mc^2
$$
인라인 수식 $a^2 + b^2 = c^2$도 사용할 수 있습니다.
---
Source: https://docs.theseeker.io/docs-sites/publishing.md
# 게시·공개 범위·주소
> 초안을 릴리스로 게시하고 공개 범위와 문서 주소를 관리합니다.
## 릴리스 게시
게시할 때 현재 사이트의 모든 페이지를 불변 스냅샷으로 저장합니다. 이후 초안 편집은 기존 릴리스를 바꾸지 않습니다. 문제가 생기면 이전 릴리스를 복원하거나 관리 화면에서 사이트 게시를 해제할 수 있습니다.
미리보기에서 페이지와 내비게이션, 링크를 확인합니다.
변경 내용을 설명하는 메시지를 입력합니다. 메시지는 최대 200자입니다.
사이트 공개 범위에 맞춰 기본 주소 또는 연결한 도메인에서 접근을 시험합니다.
## 공개 범위
| 범위 | 접근 | 검색 엔진 | 사이트맵 |
| :--- | :--- | :---: | :---: |
| 공개 | 누구나 | 색인 허용 | 포함 |
| 비공개 링크 | 링크가 있는 사용자 | noindex | 제외 |
| 비공개 | 로그인한 조직 구성원 | noindex | 제외 |
비공개 사이트의 기본 주소는 세션과 활성 조직 멤버십을 확인합니다. 연결된 커스텀 도메인에서는 비공개 사이트가 404를 반환합니다. 게시되지 않은 사이트는 공개 요청에서 찾을 수 없습니다.
기본 주소를 비활성화하면 커스텀 도메인으로 리다이렉트합니다. 커스텀 도메인이 없으면 기본 주소는 사용할 수 없습니다.
## Markdown과 LLM 파일
각 문서는 `/<경로>.md`에서 Markdown으로 받을 수 있습니다. 홈 문서는 `/index.md`입니다. 공개 페이지를 열거하는 `/llms.txt`와 전체 텍스트 `/llms-full.txt`도 제공됩니다. 숨김 페이지나 내비게이션에 배치되지 않은 페이지는 이 목록에 나타나지 않습니다.
배포 후 `/sitemap.xml`과 `/robots.txt`를 확인해 공개 범위가 검색 정책에 반영됐는지 살펴보세요.
---
Source: https://docs.theseeker.io/docs-sites/custom-domain.md
# 커스텀 도메인
> 문서 사이트를 자체 도메인에 연결하고 검증 상태를 확인합니다.
## 도메인 연결
사이트 설정에서 사용할 도메인을 입력하고 안내된 DNS 레코드를 추가합니다. Docs는 도메인 소유권과 라우팅 상태를 확인하며, 검증이 끝나면 문서 사이트가 해당 호스트에서 열립니다.
기본 주소는 `https://docs.theseeker.io/d/` 형식입니다. 커스텀 도메인을 연결하면 설정에서 기본 주소 사용 여부를 선택할 수 있습니다.
## 검증 상태
| 상태 | 의미 | 다음 작업 |
| :--- | :--- | :--- |
| 대기 | DNS 변경을 기다립니다 | 레코드와 TTL을 확인합니다 |
| 검증 중 | 소유권과 연결을 확인합니다 | 잠시 후 상태를 다시 확인합니다 |
| 활성 | 호스트가 사이트에 연결됐습니다 | HTTPS 주소를 확인합니다 |
| 실패 | 레코드가 맞지 않거나 충돌했습니다 | DNS 값과 도메인 사용처를 점검합니다 |
DNS 전파에는 시간이 걸릴 수 있습니다. 레코드를 반복해서 바꾸기보다 DNS 공급자의 응답을 먼저 확인하세요.
## 도메인 규칙
같은 도메인은 하나의 제품 리소스만 사용할 수 있습니다. 상태 페이지에서 이미 쓰는 도메인은 문서 사이트에 연결할 수 없습니다. 플랫폼에서 예약한 `docs.theseeker.io`는 `theseeker` 조직의 문서 사이트 전용입니다.
도메인 이름은 호스트명만 입력합니다. 프로토콜, 경로, 포트는 입력하지 않습니다. 사용 중인 도메인을 다른 사이트로 옮기기 전 기존 연결을 해제하세요.
커스텀 도메인의 공개 여부는 사이트 공개 범위와 별개가 아닙니다. 비공개 사이트는 커스텀 호스트에서 제공되지 않습니다.
---
Source: https://docs.theseeker.io/docs-sites/ai-authoring.md
# AI로 문서 작성 (MCP·SDK)
> MCP 도구와 TypeScript SDK로 Docs 사이트와 페이지를 관리합니다.
## AI 작성 흐름
조직 관리 API 키에 `docs:read`와 `docs:write` scope를 부여해 문서 사이트를 관리합니다. 먼저 사이트와 페이지를 조회하고, 변경 뒤 최신 revision을 기준으로 저장합니다. 검토가 끝난 경우에만 게시를 호출하세요.
`get_doc_authoring_guide`로 컴포넌트 문법과 작성 규칙을 확인합니다.
`list_doc_sites`, `list_doc_pages`, `get_doc_page`를 사용합니다.
페이지 생성·수정 도구에 Markdown 또는 정규화된 JSON을 전달합니다.
사용자의 검토가 끝난 뒤 `publish_doc_site`를 호출합니다.
AI 도구는 실제 변경을 수행합니다. 게시, 삭제, 도메인 변경은 사용자 승인을 받은 뒤 요청하세요.
## MCP 도구
읽기 도구는 `docs:read` 또는 `admin:read`, 쓰기 도구는 `docs:write` 또는 `admin:write` scope를 요구합니다. 도구는 조직 키 전용이며 project-bound key로는 사용할 수 없습니다.
| 용도 | 도구 |
| :--- | :--- |
| 가이드·사이트 조회 | `get_doc_authoring_guide`, `list_doc_sites`, `get_doc_site` |
| 페이지·릴리스 조회 | `list_doc_pages`, `get_doc_page`, `list_doc_releases` |
| 사이트·내비게이션 변경 | `create_doc_site`, `update_doc_site`, `delete_doc_site`, `set_doc_navigation` |
| 페이지 변경 | `create_doc_page`, `update_doc_page`, `delete_doc_page` |
| 게시·복원 | `publish_doc_site`, `restore_doc_release` |
사이트 설정·페이지 스키마는 [Docs API](/api-reference/docs)에서 확인할 수 있습니다.
## SDK 시작
```bash
npm install @the-seeker/docs-sdk
```
```typescript
import { createDocsClient } from "@the-seeker/docs-sdk";
const docs = createDocsClient({ apiKey: process.env.CRM_DOCS_API_KEY! });
const { page, warnings, created } = await docs.pages.upsertByPath(
"site-id",
"guides/quickstart",
{ title: "빠른 시작", markdown: "## 시작하기\n\n첫 문서입니다.\n" },
);
```
SDK 오류, timeout, 입력 계약은 [Docs SDK](/api-reference/docs-sdk)를 참고하세요.
---
Source: https://docs.theseeker.io/llm/overview.md
# LLM 안내
> LLM과 코딩 에이전트가 theseeker CRM 문서를 안정적으로 읽는 방법입니다.
## 문서 색인
문서 전체 색인은 [`/llms.txt`](https://docs.theseeker.io/llms.txt)에서 읽을 수 있습니다.
모든 페이지의 본문을 한 번에 읽으려면 [`/llms-full.txt`](https://docs.theseeker.io/llms-full.txt)를 사용하세요.
개별 문서는 브라우저 URL 끝에 `.md`를 붙여 Markdown으로 요청할 수 있습니다.
```text
https://docs.theseeker.io/server-monitoring/ai-agent-setup.md
```
또는 문서 URL에 `Accept: text/markdown` 헤더를 보내세요.
```bash
curl -H 'Accept: text/markdown' \
https://docs.theseeker.io/server-monitoring/rest-api
```
## 권장 읽기 순서
자동화 agent는 먼저 [AI 에이전트 설정](/server-monitoring/ai-agent-setup.md)을 읽어 secret 취급과 설치 제약을 확인하세요.
그 다음 [서버 REST API](/server-monitoring/rest-api.md)와 [Servers API 레퍼런스](/api-reference/servers.md)를 읽습니다.
MCP를 지원하는 에이전트는 REST 대신 [MCP 서버](/api-reference/mcp.md)를 붙여 같은 키로 도구를 호출할 수 있습니다.
## 키 취급
API key는 `THESEEKER_API_KEY` 환경 변수에서 읽고 문서, 로그, 응답 요약에 값을 출력하지 마세요.
키가 없으면 사용자에게 키 파일 경로를 물어보고, 임시 파일을 쓸 때는 mode `600`을 사용한 뒤 삭제합니다.
## 권장 호출 흐름
1. `GET /api/v1/servers?projectSlug=`로 키와 프로젝트 범위를 확인합니다.
2. `POST /api/v1/servers`로 서버를 등록합니다.
3. 응답의 1회성 token으로 에이전트를 설치합니다.
4. `GET /api/v1/servers/`에서 60초 안에 `state: online`을 확인합니다.
오류가 발생하면 [Errors와 Rate Limits](/api-reference/errors-and-rate-limits.md)의 code와 `Retry-After`를 기준으로 처리하세요.
---
Source: https://docs.theseeker.io/api-reference/authentication.md
# Authentication
> CRM API의 Bearer 인증 형식과 키 범위를 설명하는 레퍼런스입니다.
## Bearer 인증
`/api/v1` 관리 API는 다음 형식의 Bearer token을 받습니다.
```http
Authorization: Bearer .
```
실제 값은 환경 변수에서 읽으세요.
```bash
curl -sS https://crm.theseeker.io/api/v1/servers \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
## 키 종류와 범위
| 키 | 프로젝트 범위 | 서버 API |
| --- | --- | --- |
| 프로젝트 키 | 발급된 프로젝트로 고정 | `servers:read`, `servers:write` |
| 조직 키 | 조직 전체 프로젝트 | `servers:read`, `servers:write` |
`admin:read`는 읽기 endpoint를, `admin:write`는 변경 endpoint를 함께 승인합니다.
요청은 키에 부여된 scope 중 하나라도 endpoint 요구사항과 맞으면 승인됩니다.
## 응답 헤더
인증 응답에는 현재 scope 기반 enforcement를 나타내는 `X-Key-Enforcement: scopes` 헤더가 포함될 수 있습니다.
## 인증 실패
토큰 누락, 형식 오류, 잘못된 secret, 폐기된 키는 `401 UNAUTHORIZED`입니다.
유효한 키지만 필요한 scope가 없으면 `403 FORBIDDEN_SCOPE`입니다.
IP allowlist 밖의 요청은 `403 ip_not_allowed`입니다.
## 보안
secret은 발급 직후 한 번만 표시됩니다. URL query string, 로그, 소스 코드에 넣지 마세요.
---
Source: https://docs.theseeker.io/api-reference/errors-and-rate-limits.md
# Errors와 Rate Limits
> 공통 오류 envelope, HTTP status, 서버 API의 요청 제한을 정리합니다.
## 오류 형식
모든 오류는 다음 JSON envelope을 사용합니다.
```json
{"error":{"code":"ERROR_CODE","message":"설명"}}
```
`message`는 사람이 읽을 수 있는 설명이고, 프로그램 분기는 안정적인 `code`를 사용하세요.
## 공통 status
| HTTP | Code | 의미 |
| ---: | --- | --- |
| 400 | `VALIDATION_ERROR` | body 또는 query 검증 실패 |
| 401 | `UNAUTHORIZED` | 인증 실패 |
| 403 | `FORBIDDEN_SCOPE` | scope 부족 |
| 403 | `project_forbidden` | 프로젝트 키 범위 밖 |
| 403 | `ip_not_allowed` | IP allowlist 밖 |
| 404 | 리소스별 code | 대상이 없음 |
| 409 | `SLUG_TAKEN` | slug 충돌 |
| 429 | `RATE_LIMITED` | 요청 한도 초과 |
| 429 | `BUDGET_EXCEEDED` | MCP 일일 호출 예산 초과 |
## 서버 API 오류
서버 endpoint는 `SERVER_NOT_FOUND`, `PROJECT_NOT_FOUND`, `reserved_project_forbidden`을 추가로 반환할 수 있습니다.
프로젝트 키로 다른 프로젝트의 서버를 조회하면 존재 여부를 숨기기 위해 `SERVER_NOT_FOUND`가 반환됩니다.
## Rate limit
`/api/v1/servers*`는 keyId별로 60초에 60회까지 허용합니다. 61번째 요청은 `429`입니다.
응답에는 `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` 헤더가 포함됩니다.
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
```
`Retry-After`를 기다린 후 재시도하고, 여러 키를 임의로 번갈아 사용해 제한을 우회하지 마세요.
---
Source: https://docs.theseeker.io/api-reference/projects.md
# Projects API
> 조직 안에 프로젝트를 생성하고 관리 API로 조회하는 방법입니다.
## POST /api/v1/projects
관리 API 키의 `admin:write`가 필요합니다.
```http
POST /api/v1/projects HTTP/1.1
Host: crm.theseeker.io
Authorization: Bearer .
Content-Type: application/json
{"slug":"payments","name":"Payments"}
```
## 요청 필드
| 필드 | 타입 | 설명 |
| --- | --- | --- |
| `slug` | string | 조직에서 유일한 API 식별자 |
| `name` | string | 표시 이름 |
성공 시 `201`과 `project` 객체를 반환합니다.
```json
{"project":{"id":"project-id","slug":"payments","name":"Payments","createdAt":"2026-01-01T00:00:00.000Z"}}
```
## 오류
잘못된 body는 `400 VALIDATION_ERROR`, 같은 slug는 `409 SLUG_TAKEN`입니다.
인증이 없으면 `401 UNAUTHORIZED`, 쓰기 scope가 없으면 `403 FORBIDDEN_SCOPE`입니다.
## 프로젝트와 하위 리소스
모니터, 피드백, 서버는 프로젝트에 연결됩니다. 프로젝트 slug를 query나 body에 넣을 때는 현재 키의 범위를 확인하세요.
프로젝트 키는 자신이 발급된 프로젝트만 대상으로 합니다.
---
Source: https://docs.theseeker.io/api-reference/monitors.md
# Monitors API
> 모니터 생성, 목록 조회, 수정, 삭제 endpoint의 기본 계약입니다.
## Endpoint
| Method | Path | Scope |
| --- | --- | --- |
| `GET` | `/api/v1/monitors?projectSlug=` | `admin:read` 또는 `status:read` |
| `POST` | `/api/v1/monitors` | `admin:write` |
| `PATCH` | `/api/v1/monitors/:id` | `admin:write` |
| `DELETE` | `/api/v1/monitors/:id` | `admin:write` |
## 생성
```bash
curl -X POST https://crm.theseeker.io/api/v1/monitors \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"projectSlug":"payments","slug":"checkout-api","name":"Checkout API","intervalSec":60,"degradedAfter":120,"downAfter":240}'
```
성공 status는 `201`이고 `{ "monitor": ... }`를 반환합니다. `slug`는 프로젝트에서 유일해야 합니다.
## 목록
```bash
curl 'https://crm.theseeker.io/api/v1/monitors?projectSlug=payments' \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
성공 응답은 `{ "monitors": [...] }`입니다. API 키의 조직 또는 프로젝트 범위에 따라 결과가 제한됩니다.
## 오류
검증 실패는 `400`, 권한 부족은 `403`, 없는 monitor는 `404`, slug 충돌은 `409`입니다.
상태 이벤트는 프로젝트 키로 ingest endpoint에 보내며, 이 관리 endpoint와 같은 키를 혼용하지 마세요.
## 응답 형태
목록 응답의 최상위 키는 `monitors`이고 생성 응답의 최상위 키는 `monitor`입니다.
날짜 값은 API 응답에서 ISO 형식 문자열로 직렬화됩니다.
---
Source: https://docs.theseeker.io/api-reference/status-page.md
# Status Page API
> 상태 페이지 조회와 부분 수정, 커스텀 도메인 검증 endpoint를 설명합니다.
## Endpoint
| Method | Path | 설명 |
| --- | --- | --- |
| `GET` | `/api/v1/status-page` | 상태 페이지 조회 |
| `PATCH` | `/api/v1/status-page` | 설정 부분 수정 |
| `GET` | `/api/v1/status-page/domain-verification` | DNS와 HTTPS 연결 확인 |
모든 endpoint는 관리 API 인증을 사용합니다.
## 조회
```bash
curl -sS https://crm.theseeker.io/api/v1/status-page \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
성공 응답은 `statusPage` 안에 `enabled`, `slug`, `title`, `description`, `customDomain`, `publicUrl`, `customDomainUrl`, `components`를 포함합니다.
페이지가 없으면 `404 NOT_FOUND`입니다.
## 부분 수정
허용 필드는 `enabled`, `slug`, `title`, `description`, `customDomain`입니다. 생략한 필드는 유지됩니다.
```bash
curl -X PATCH https://crm.theseeker.io/api/v1/status-page \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"enabled":true,"customDomain":"status.example.com"}'
```
`customDomain: null`은 도메인을 제거합니다. 잘못된 필드는 `400`, slug 충돌은 `409 SLUG_TAKEN`입니다.
## 도메인 검증
검증 결과의 `status`는 `dns_missing`, `dns_mismatch`, `dns_ok_tls_pending`, `active` 중 하나입니다.
`active`는 라우팅 확인이며 소유권 증명은 아닙니다.
---
Source: https://docs.theseeker.io/api-reference/feedback.md
# Feedback API
> 조직의 피드백을 조회하고 프로젝트 키로 전송하는 경계를 설명합니다.
## GET /api/v1/feedback
피드백 목록 조회에는 `admin:read` 또는 `feedback:read`가 필요합니다.
```bash
curl -sS https://crm.theseeker.io/api/v1/feedback \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
응답은 인증 키가 허용하는 조직 또는 프로젝트 범위 안에서 반환됩니다.
## 이벤트 전송
피드백 전송은 프로젝트 ingest 경로를 사용합니다. Status SDK에서는 `sendFeedback`으로 호출합니다.
```ts
await status.sendFeedback({
uid: "user-123",
content: "검색 결과가 느립니다.",
fields: { plan: "pro" },
});
```
이 요청에는 프로젝트 키와 SDK가 생성하는 서명 헤더가 필요합니다. 관리 API Bearer 키를 ingest HMAC 키 대신 사용하지 마세요.
## 필드
| 필드 | 설명 |
| --- | --- |
| `uid` | 호출자가 정한 사용자 식별자 |
| `content` | 피드백 본문 |
| `fields` | 검색 가능한 추가 필드 |
| `extra` | 부가 문맥 |
## 응답 필드
`GET /api/v1/feedback`은 `feedbacks` 배열과 페이지네이션용 `nextCursor`를 반환합니다. 각 항목은 기존 ID, 사용자 ID, 본문, 발생·수신 시각, `fields`, `extra`에 다음 필드를 추가로 포함합니다.
| 필드 | 형식 | 설명 |
| --- | --- | --- |
| `status` | string | `new`, `in_progress`, `resolved`, `closed` |
| `tags` | string\[\] | 피드백 분류 태그 |
| `kind` | string | `feedback`, `nps`, `csat` |
| `source` | string | `sdk`, `widget`, `survey` |
| `score` | number 또는 null | NPS/CSAT 점수 |
| `pageUrl` | string 또는 null | 응답 페이지 URL |
| `contactEmail` | string 또는 null | 제출자가 제공한 연락 이메일 |
| `sessionId` | string 또는 null | 연결된 분석 세션 |
| `propertyId` | string 또는 null | 연결된 분석 프로퍼티 |
| `relatedIssueIds` | string\[\] | 연결된 에러 이슈 ID |
| `browser`, `os`, `device` | string 또는 null | 방문자 환경 정보 |
| `hasScreenshot` | boolean | 스크린샷 첨부 존재 여부 |
| `updatedAt` | ISO 시각 또는 null | 마지막 갱신 시각 |
## 위젯 제출
공개 위젯은 `POST /api/feedback/widget`로 JSON을 전송합니다. config는 `GET /api/feedback/widget/config?key=fbw_…`로 조회합니다. 허용 도메인에서 온 Origin이 필요합니다. 설정과 제출의 CORS 응답은 허용 Origin에 한하며, preflight는 `POST, OPTIONS`와 `Content-Type`을 허용합니다.
본문에는 `key`, `kind`, `content`, `pageUrl`을 보내고 선택적으로 `contactEmail`, `uid`, JPEG data URL `screenshot`, `surveyId`, `score`를 포함합니다. 일반 피드백 본문은 1~~5,000자이며 설문은 0~~5,000자입니다. NPS 점수는 0~~10, CSAT은 1~~5입니다. 요청 최대 크기는 2 MiB이며, 스크린샷은 JPEG 시그니처와 최대 1,572,864바이트를 요구합니다. IP/key 조합당 10분 10회, key당 10분 100회로 제한됩니다. 성공 시 `201 {"id":"…"}`를 반환합니다. 설문 제출은 현재 활성 설문 ID와 유형이 일치해야 합니다.
## 오류
조회 인증 실패는 `401`, scope 부족은 `403`, 잘못된 요청은 `400`입니다.
secret과 개인정보가 서버 로그나 피드백 본문에 섞이지 않도록 호출 전에 정제하세요.
---
Source: https://docs.theseeker.io/api-reference/sourcemaps.md
# Source Maps API
> 릴리스별 JavaScript source map 업로드, 조회, 삭제 API입니다.
## 인증과 scope
`Authorization: Bearer .` 형식의 프로젝트 키를 사용합니다. POST와 DELETE에는 `errors:write` 또는 `admin:write`, GET에는 `errors:write`, `admin:read`, `admin:write` 중 하나가 필요합니다. 요청은 키가 속한 조직의 프로퍼티로 제한됩니다. 키당 분당 60회로 제한됩니다.
```text
POST /api/v1/sourcemaps
GET /api/v1/sourcemaps?domain=example.com
DELETE /api/v1/sourcemaps?domain=example.com&release=web-1.2.3
```
## POST multipart 업로드
필드 `release`와 `domain` 또는 `propertyId` 중 하나를 먼저 지정하고, 각 파일마다 `file`과 `path`를 같은 순서로 반복합니다. `file`은 v3 source-map JSON 파일이고 `path`는 브라우저가 요청하는 minified 파일의 URL 또는 경로입니다.
```bash
curl -X POST https://crm.theseeker.io/api/v1/sourcemaps \
-H "Authorization: Bearer $THESEEKER_API_KEY" \
-F 'release=web-1.2.3' -F 'domain=example.com' \
-F 'file=@.next/static/chunks/app.js.map;type=application/json' \
-F 'path=https://example.com/_next/static/chunks/app.js'
```
`path`는 HTTP(S) URL이면 pathname만 쓰고, `file://` URL이면 URL pathname을 사용합니다. `/abs/path`는 그대로 유지하고 `~/path`는 `/path`로 정규화합니다. query와 hash는 제거됩니다. 소스맵은 `version: 3`이어야 하며 string `mappings` 또는 `sections` 배열이 있어야 합니다. 같은 프로퍼티·릴리스·경로의 업로드는 기존 파일을 교체합니다.
| 제한 | 값 | 초과 시 |
| --- | ---: | --- |
| 파일 수 | 요청당 100개 | 413 `TOO_MANY_FILES` |
| 파일 크기 | 파일당 15 MiB | 413 `FILE_TOO_LARGE` |
| 요청 크기 | 요청당 40 MiB | 413 `PAYLOAD_TOO_LARGE` |
| 릴리스 파일 | 릴리스당 1,000개 | 409 `RELEASE_FILE_LIMIT` |
| 저장 공간 | 프로퍼티당 압축 기준 1 GiB | 409 `QUOTA_EXCEEDED` |
| 요청 빈도 | 키당 분당 60회 | 429, `Retry-After` |
성공하면 `201`과 함께 다음 형태를 반환합니다.
```json
{"release":"web-1.2.3","propertyId":"...","uploaded":[{"path":"/_next/static/chunks/app.js","size":12345,"sha256":"..."}]}
```
## GET 파일 조회
프로퍼티 선택자에 `release`를 생략하면 릴리스별 요약을 반환합니다.
```bash
curl -sS 'https://crm.theseeker.io/api/v1/sourcemaps?domain=example.com' \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
응답은 `{ "releases": [{ "release", "files", "totalSize", "lastUploadedAt" }] }`입니다. `release`를 지정하면 해당 릴리스의 파일 목록을 받습니다.
```bash
curl -sS 'https://crm.theseeker.io/api/v1/sourcemaps?domain=example.com&release=web-1.2.3' \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
파일 항목은 `path`, `size`, `compressedSize`, `sha256`, `createdAt`을 포함합니다.
## DELETE 릴리스
```bash
curl -X DELETE 'https://crm.theseeker.io/api/v1/sourcemaps?domain=example.com&release=web-1.2.3' \
-H "Authorization: Bearer $THESEEKER_API_KEY"
```
성공 응답은 `{ "deleted": 3 }`처럼 삭제한 파일 수를 반환합니다. `propertyId`로도 프로퍼티를 지정할 수 있습니다.
## 오류 응답
| HTTP | 코드 | 설명 |
| ---: | --- | --- |
| 400 | `VALIDATION_ERROR` | release, 프로퍼티 선택자 또는 multipart 필드가 잘못됨 |
| 400 | `INVALID_SOURCE_MAP` | v3 source-map JSON이 아니거나 필수 필드가 없음 |
| 401 | `UNAUTHORIZED` | 인증 정보가 없거나 유효하지 않음 |
| 403 | `FORBIDDEN_SCOPE` | 해당 작업의 scope가 없음 |
| 404 | `PROPERTY_NOT_FOUND` | 키 조직에 속한 프로퍼티를 찾을 수 없음 |
| 409 | `RELEASE_FILE_LIMIT` | 릴리스 파일 수 한도 초과 |
| 409 | `QUOTA_EXCEEDED` | 프로퍼티 저장 용량 초과 |
| 413 | `TOO_MANY_FILES` | 한 요청의 파일 수 초과 |
| 413 | `FILE_TOO_LARGE` | 파일 크기 초과 |
| 413 | `PAYLOAD_TOO_LARGE` | 전체 요청 크기 초과 |
| 429 | `RATE_LIMITED` | 키당 분당 요청 한도 초과, `Retry-After` 확인 |
인증이나 scope 오류는 공통 API 오류 envelope를 사용합니다. 소스맵 파일을 공개 사이트에 남기지 마세요. 업로드 후 빌드의 `.map` 파일을 삭제해야 합니다.
---
Source: https://docs.theseeker.io/api-reference/servers.md
# Servers API
> 서버 목록, 등록, 상세, 수정, 삭제, 토큰 재발급의 REST 계약입니다.
## Endpoint 요약
| Method | Path | Scope |
| --- | --- | --- |
| `GET` | `/api/v1/servers?projectSlug=` | `admin:read` 또는 `servers:read` |
| `POST` | `/api/v1/servers` | `admin:write` 또는 `servers:write` |
| `GET` | `/api/v1/servers/{id}` | `admin:read` 또는 `servers:read` |
| `PATCH` | `/api/v1/servers/{id}` | `admin:write` 또는 `servers:write` |
| `DELETE` | `/api/v1/servers/{id}` | `admin:write` 또는 `servers:write` |
| `POST` | `/api/v1/servers/{id}/rotate-token` | `admin:write` 또는 `servers:write` |
## 인증과 목록
```http
Authorization: Bearer .
```
`GET /servers?projectSlug=`는 `{ "servers": [...] }`를 반환합니다. 조직 키는 조직 전체를 보고, 프로젝트 키는 자신의 프로젝트만 봅니다.
## 생성 요청과 응답
요청 body는 다음 필드를 받을 수 있습니다.
| 필드 | 타입 | 설명 |
| --- | --- | --- |
| `projectSlug` | string? | 프로젝트 키는 생략 가능 |
| `name` | string | 서버 표시 이름 |
| `slug` | string? | 서버 식별자 |
| `intervalSec` | number? | 10에서 60초, 기본 15 |
| `watchedServices` | string\[\]? | 감시할 systemd unit |
| `nginxEnabled` | boolean? | nginx 수집 여부 |
`201` 응답은 `{ server, token, agentEndpoint, install: { ubuntu, macos, nvm } }`입니다. `token`은 1회만 표시됩니다.
```json
{ "server": { "state": "unknown" }, "token": "", "agentEndpoint": "wss://", "install": { "ubuntu": "...", "macos": "...", "nvm": "..." } }
```
상태 행은 에이전트의 첫 heartbeat에서 생성되므로 등록 직후 `state`는 `unknown`입니다.
## 상세와 변경
상세 `server`는 `state`(`unknown`, `online`, `offline`), `lastSeenAt`, `agentVersion`, 최신 metrics를 포함합니다.
PATCH는 `name`, `intervalSec`, `watchedServices`, `nginxEnabled`를 부분 수정합니다.
## 오류
`401 UNAUTHORIZED`, `403 FORBIDDEN_SCOPE`, `403 project_forbidden`, `403 reserved_project_forbidden`, `403 ip_not_allowed`, `404 SERVER_NOT_FOUND`, `404 PROJECT_NOT_FOUND`, `400 VALIDATION_ERROR`, `409 SLUG_TAKEN`을 반환할 수 있습니다.
## Token rotation과 제한
`POST /servers/{id}/rotate-token`은 이전 토큰을 무효화하고 새 `token`, `agentEndpoint`, `install`을 반환합니다.
회전 응답의 `server.state`는 현재 상태를 반영하며, 상태 행이 없으면 `unknown`입니다.
```json
{ "server": { "state": "online" }, "token": "", "agentEndpoint": "wss://", "install": { "ubuntu": "...", "macos": "...", "nvm": "..." } }
```
서버 API 전체는 keyId마다 60초 60회로 제한되며 초과 시 `429 RATE_LIMITED`와 `Retry-After`를 반환합니다.
---
Source: https://docs.theseeker.io/api-reference/docs.md
# Docs API
> 조직 API 키로 문서 사이트, 페이지, 내비게이션과 릴리스를 관리합니다.
## 인증과 제한
모든 요청은 `Authorization: Bearer .` 헤더를 사용합니다. 읽기 요청에는 `docs:read` 또는 `admin:read`, 변경 요청에는 `docs:write` 또는 `admin:write`가 필요합니다. 프로젝트 범위 키는 사용할 수 없습니다. API는 키별 분당 120회로 제한됩니다.
조직 관리 API 키의 Bearer 인증 값입니다.
JSON 본문을 보내는 요청에 `application/json`을 지정합니다.
## 엔드포인트
| Method | 경로 | 기능 |
| :---: | :--- | :--- |
| GET | `/api/v1/docs/authoring-guide` | 작성 가이드와 컴포넌트 목록 |
| GET, POST | `/api/v1/docs/sites` | 사이트 목록, 생성 |
| GET, PATCH, DELETE | `/api/v1/docs/sites/{siteId}` | 사이트 조회, 수정, 삭제 |
| GET, PUT | `/api/v1/docs/sites/{siteId}/navigation` | 내비게이션 조회와 전체 교체 |
| GET, POST | `/api/v1/docs/sites/{siteId}/pages` | 페이지 목록, 경로 조회, 생성 |
| GET, PATCH, DELETE | `/api/v1/docs/sites/{siteId}/pages/{pageId}` | 페이지 조회, 수정, 삭제 |
| POST | `/api/v1/docs/sites/{siteId}/publish` | 새 릴리스 게시 |
| GET | `/api/v1/docs/sites/{siteId}/releases` | 릴리스 목록 |
| POST | `/api/v1/docs/sites/{siteId}/releases/{releaseId}/restore` | 릴리스 복원 |
### 사이트 조회와 생성
```http
GET /api/v1/docs/sites
```
```json
{"sites":[{"id":"site-id","slug":"product","name":"제품 문서","visibility":"public","published":true}]}
```
```http
POST /api/v1/docs/sites
Content-Type: application/json
```
```json
{"slug":"product","name":"제품 문서","description":"제품 사용 안내","visibility":"public"}
```
성공 시 `201`과 `{ "site": ... }`를 반환합니다. 사이트 이름은 1~80자입니다.
### 사이트 조회·수정·삭제
`GET /api/v1/docs/sites/{siteId}`는 사이트, 내비게이션, 게시 정보를 반환합니다. `PATCH`는 이름, slug, 설명, 공개 범위, 기본 주소, 커스텀 도메인과 설정을 변경합니다. 사이트 삭제는 확인용 slug를 본문으로 요구합니다.
```http
DELETE /api/v1/docs/sites/{siteId}
Content-Type: application/json
```
```json
{"confirmSlug":"product"}
```
응답은 `{"deleted":true}`입니다.
### 내비게이션
```http
PUT /api/v1/docs/sites/{siteId}/navigation
Content-Type: application/json
```
내비게이션 입력의 `tabs`와 `groups`는 동시에 비어 있지 않을 수 없습니다. 입력은 전체 교체 방식이며 배열 순서가 표시 순서를 정합니다.
```json
{"navigation":{"tabs":[],"groups":[{"title":"가이드","pages":[{"path":"","children":[]}]}]}}
```
### 페이지 조회와 생성
`GET .../pages?path=guides/start`는 경로로 페이지를 찾습니다. 생성 본문은 `markdown` 또는 `contentJson` 중 하나를 받습니다.
페이지 경로입니다. 홈 페이지 경로는 빈 문자열입니다.
페이지 제목입니다.
Mintlify MDX 형식의 본문입니다. `contentJson`과 동시에 보낼 수 없습니다.
페이지를 배치할 그룹입니다. 생략하면 첫 그룹에 추가합니다.
```bash title="페이지 생성"
curl -X POST https://crm.theseeker.io/api/v1/docs/sites/site-id/pages \
-H "Authorization: Bearer ." \
-H "Content-Type: application/json" \
-d '{"path":"guides/start","title":"시작하기","markdown":"## 시작\n"}'
```
`201` 응답은 `{ "page", "warnings" }`입니다. 페이지 수정은 `PATCH`를 사용하고, `baseRevision`이 현재 revision과 다르면 `409 CONFLICT`를 반환합니다. 페이지 삭제 응답은 `{"deleted":true}`입니다.
### 페이지 수정과 조회
```http
PATCH /api/v1/docs/sites/{siteId}/pages/{pageId}
```
```json
{"baseRevision":4,"title":"시작하기","markdown":"## 시작\n\n새 본문\n"}
```
`GET`은 페이지 메타데이터와 Markdown을 반환합니다. `?includeJson=1`을 지정하면 canonical content JSON도 포함됩니다.
### 게시와 릴리스
```http
POST /api/v1/docs/sites/{siteId}/publish
Content-Type: application/json
```
```json
{"message":"첫 문서 릴리스"}
```
게시 성공은 `201 { "release", "urls" }`입니다. `GET .../releases?limit=20`에서 최대 100개를 조회하고, `POST .../releases/{releaseId}/restore`로 기존 릴리스를 게시 상태로 복원합니다.
## 응답 필드와 오류
페이지 초안의 낙관적 동시성 번호입니다. 저장할 때 기준 revision을 보내세요.
Markdown 변환 중 발견한 알림입니다. 반환된 문서 내용을 확인하세요.
| Status | Code | 의미 |
| ---: | :--- | :--- |
| 400 | `VALIDATION_ERROR` | 입력 검증 실패 |
| 400 | `BAD_REQUEST` | JSON 본문을 읽을 수 없음 |
| 403 | `FORBIDDEN_SCOPE` | 필요한 scope 없음 |
| 403 | `FORBIDDEN_PROJECT` | project-bound key 사용 |
| 404 | `NOT_FOUND` | 리소스 없음 |
| 409 | `CONFLICT` | revision 또는 식별자 충돌 |
| 429 | `RATE_LIMITED` | 키별 요청 한도 초과 |
```json
{"error":{"code":"CONFLICT","message":"페이지가 다른 곳에서 수정되었습니다."}}
```
---
Source: https://docs.theseeker.io/api-reference/docs-sdk.md
# Docs SDK
> TypeScript에서 Docs REST API를 호출하는 공식 npm 클라이언트를 사용합니다.
## 설치
```bash
npm install @the-seeker/docs-sdk
```
SDK는 ESM 패키지이며 Node.js 18.17 이상을 지원합니다.
## 클라이언트 만들기
```typescript
import { createDocsClient } from "@the-seeker/docs-sdk";
const apiKey = process.env.CRM_DOCS_API_KEY;
if (!apiKey) throw new Error("CRM_DOCS_API_KEY가 필요합니다.");
const docs = createDocsClient({ apiKey });
const { sites } = await docs.sites.list();
```
`docs:read` 또는 `docs:write` 권한을 가진 조직 API 키입니다.
API 기본 주소입니다. 테스트 환경에서만 재정의하세요.
요청 제한 시간(밀리초)입니다.
## 페이지 생성과 경로 upsert
`create`는 페이지를 새로 만들고, `upsertByPath`는 같은 경로의 페이지가 있으면 수정합니다. 반환값의 `created`는 실제 생성 여부이며 `warnings`는 Markdown 변환 결과를 알립니다.
```typescript
const result = await docs.pages.upsertByPath("site-id", "guides/start", {
title: "시작하기",
markdown: "## 시작하기\n\n첫 문서입니다.\n",
});
console.log(result.page.path, result.created, result.warnings);
```
수정 요청에서 `baseRevision`을 사용하면 동시에 진행된 편집을 감지할 수 있습니다. 충돌이면 페이지를 다시 읽고 변경을 합치세요.
## 클라이언트 메서드
| 영역 | 메서드 |
| :--- | :--- |
| 가이드 | `authoringGuide()` |
| 사이트 | `sites.list()`, `get()`, `create()`, `update()`, `delete()` |
| 내비게이션 | `navigation.get()`, `navigation.set()` |
| 페이지 | `pages.list()`, `get()`, `getByPath()`, `create()`, `update()`, `delete()`, `upsertByPath()` |
| 게시와 릴리스 | `publish()`, `releases.list()`, `releases.restore()` |
## 오류 처리
HTTP 요청이 실패하면 `DocsApiError`가 발생합니다. `status`는 HTTP 상태 코드, `code`는 서버가 돌려준 오류 코드입니다.
```typescript
import { DocsApiError } from "@the-seeker/docs-sdk";
try {
await docs.pages.create("site-id", {
path: "guides/start",
title: "시작하기",
markdown: "본문\n",
});
} catch (error) {
if (error instanceof DocsApiError) {
console.error(error.status, error.code);
} else {
throw error;
}
}
```
오류 코드와 REST 응답은 [Docs API](/api-reference/docs#응답-필드와-오류)를 참고하세요.
---
Source: https://docs.theseeker.io/api-reference/mcp.md
# MCP
> API 키로 인증하는 MCP 서버 엔드포인트와 클라이언트 설정
## 개요
theseeker CRM은 MCP(Model Context Protocol) 서버를 제공합니다. MCP를 지원하는 AI 코딩 에이전트는 이 서버를 붙이면
프로젝트, 모니터, 인시던트, 상태 페이지, 애널리틱스, 오류, 피드백, 서버와 문서 사이트 리소스를 60개 도구로 직접 읽고 바꿀 수 있습니다.
대상 클라이언트는 opencode, Claude Code, Cursor처럼 원격 MCP 서버를 지원하는 도구이며,
opencode-dashboard의 "CRM MCP" 탭에서도 같은 엔드포인트를 사용합니다.
REST API와 기능 범위는 같고, 인증도 [API 키](/getting-started/api-keys) 하나를 그대로 씁니다.
## 인증
MCP 요청은 REST API와 같은 Bearer 형식을 사용합니다.
```http
Authorization: Bearer .
```
키에 부여된 scope가 도구의 요구 scope 중 하나라도 만족하면 호출이 승인됩니다.
| Scope | 의미 |
| --- | --- |
| `status:read` | 상태 데이터 조회 |
| `status:write` | 상태 이벤트 전송 |
| `feedback:read` | 피드백 조회 |
| `feedback:write` | 피드백 전송 |
| `analytics:write` | 레거시 분석 이벤트 전송 |
| `admin:read` | 관리 리소스 조회 |
| `admin:write` | 관리 리소스 변경 |
| `servers:read` | 서버 목록과 상세 조회 |
| `servers:write` | 서버 등록, 수정, 삭제, 토큰 재발급 |
| `docs:read` | 문서 사이트와 페이지 조회 |
| `docs:write` | 문서 사이트 작성·게시 |
키 종류에 따라 대상 범위가 달라집니다.
- **프로젝트 키**(ingest 계열): 발급된 프로젝트에 고정됩니다. 다른 프로젝트를 지정하면 거부되고, 목록 도구는 자기 프로젝트만 돌려줍니다.
- **조직 관리 API 키**: 조직 전체 프로젝트를 대상으로 합니다. 아래 표에서 "조직 키 전용"이 `O`인 도구는 조직 키로만 호출할 수 있습니다.
secret은 발급 직후 한 번만 표시됩니다. 키는 mode-600 파일이나 secret manager에 두고 설정 파일에 평문으로 넣지 마세요.
## 엔드포인트
```text
POST https://crm.theseeker.io/api/mcp
```
- 무상태(stateless) Streamable HTTP 전송이며 세션 ID를 유지하지 않습니다. 응답은 항상 JSON입니다.
- `POST`만 허용합니다. `GET`과 `DELETE`는 `405`입니다.
- 요청에는 `Content-Type: application/json`과 `Accept: application/json, text/event-stream` 헤더가 모두 필요합니다. 빠지면 `406`입니다.
- 표준 MCP 흐름(`initialize` → `tools/list` → `tools/call`)을 그대로 따릅니다.
## 도구 목록
도구 입력에서 프로젝트는 `projectId` 또는 `projectSlug`로 지정합니다(프로젝트 키는 생략 가능).
결과는 사람이 읽는 텍스트와 함께 `structuredContent`에 같은 데이터를 JSON으로 담아 돌려줍니다.
| 도구 | 필요 스코프 (OR) | 조직 키 전용 | 설명 |
| --- | --- | :---: | --- |
| `get_api_key_info` | (없음) | X | 현재 키의 스코프·프로젝트·사용 가능 도구 표 |
| `list_projects` | `admin:read`, `status:read` | X | 프로젝트 목록 (프로젝트 키는 자기 프로젝트만) |
| `create_project` | `admin:write` | O | 프로젝트 생성 |
| `list_monitors` | `admin:read`, `status:read` | X | 모니터 목록 + 최신 상태 |
| `get_monitoring_snapshot` | `admin:read`, `status:read` | X | 업타임·인시던트·하트비트 스냅샷 (`monitorId?`, `uptimeDays?` 1..90) |
| `create_monitor` | `admin:write` | X | 모니터 생성 |
| `update_monitor` | `admin:write` | X | 모니터 수정 |
| `delete_monitor` | `admin:write` | X | 모니터 삭제 |
| `list_incidents` | `admin:read`, `status:read` | X | 인시던트 목록 (`projectId?`, `projectSlug?`, `status?`, `limit` 1..100) |
| `get_incident` | `admin:read`, `status:read` | X | 인시던트 상세·업데이트 조회 (`incidentId`) |
| `create_incident` | `admin:write` | X | 모니터 인시던트 생성 (`title`, `severity`, `monitorIds`, `initialBody`) |
| `post_incident_update` | `admin:write` | X | 인시던트 상태·메시지 게시 (`incidentId`, `status`, `body`) |
| `resolve_incident` | `admin:write` | X | 인시던트 해결 (`incidentId`, `body?`) |
| `get_status_page` | `admin:read`, `status:read` | O | 상태 페이지 설정 조회 |
| `get_public_status_snapshot` | `admin:read`, `status:read` | O | 공개 상태 페이지 스냅샷 |
| `update_status_page` | `admin:write` | O | 상태 페이지 설정 수정 |
| `list_analytics_properties` | `admin:read` | O | 애널리틱스 속성 설정 조회 |
| `list_analytics_goals` | `admin:read` | O | 애널리틱스 목표 설정 조회 |
| `get_analytics_snapshot` | `admin:read` | O | 애널리틱스 값 스냅샷 (`propertyId`, `period` 7d/30d/90d) |
| `list_analytics_funnels` | `admin:read` | O | 속성의 퍼널 목록 (`propertyId`) |
| `get_analytics_funnel_result` | `admin:read` | O | 퍼널 전환 결과 (`funnelId`, `period` 기본 30d) |
| `get_web_vitals` | `admin:read` | O | 웹 바이탈 (`propertyId`, `period` 기본 30d) |
| `create_analytics_property` | `admin:write` | O | 애널리틱스 속성 생성 |
| `update_analytics_property` | `admin:write` | O | 애널리틱스 속성 수정 |
| `delete_analytics_property` | `admin:write` | O | 애널리틱스 속성 삭제 |
| `create_analytics_goal` | `admin:write` | O | 애널리틱스 목표 생성 |
| `update_analytics_goal` | `admin:write` | O | 애널리틱스 목표 수정 |
| `delete_analytics_goal` | `admin:write` | O | 애널리틱스 목표 삭제 |
| `list_error_issues` | `admin:read` | O | 오류 이슈 목록 |
| `get_error_issue` | `admin:read` | O | 오류 이슈 상세 |
| `get_error_fix_context` | `admin:read` | O | 오류 수정 브리프(요약·기호화 스택·브레드크럼·관련 피드백·세션 타임라인·markdown), `issueId`, `sampleLimit` 1..5 |
| `list_error_types` | `admin:read` | O | 오류 유형 목록 |
| `update_error_issue_status` | `admin:write` | O | 오류 이슈 resolve/ignore/reopen |
| `get_feedback_fields` | `admin:read`, `feedback:read` | X | 피드백 필드 설정 조회 |
| `list_feedback` | `admin:read`, `feedback:read` | X | 피드백 목록 |
| `get_feedback` | `admin:read`, `feedback:read` | X | 피드백 상세·연관 오류 (`feedbackId`) |
| `update_feedback_fields` | `admin:write` | X | 피드백 필드 설정 변경 |
| `update_feedback_triage` | `admin:write` | X | 피드백 상태·태그·연관 오류 수정 (`feedbackId`, `status?`, `tags?`, `relatedIssueIds?` 중 하나 이상) |
| `list_servers` | `admin:read`, `servers:read` | X | 서버 목록 |
| `get_server` | `admin:read`, `servers:read` | X | 서버 상세 |
| `create_server` | `admin:write`, `servers:write` | X | 서버 등록 |
| `update_server` | `admin:write`, `servers:write` | X | 서버 수정 |
| `delete_server` | `admin:write`, `servers:write` | X | 서버 삭제 |
| `rotate_server_token` | `admin:write`, `servers:write` | X | 서버 토큰 회전 |
| `tail_server_logs` | `admin:write`, `servers:write` | X | 서버 에이전트 로그 요청 (`serverId`, `sourceId`, `lines` 100/200/500) |
| `get_doc_authoring_guide` | `docs:read`, `admin:read` | O | 작성 가이드와 컴포넌트 목록 |
| `list_doc_sites` | `docs:read`, `admin:read` | O | 조직의 문서 사이트 목록 |
| `get_doc_site` | `docs:read`, `admin:read` | O | 사이트 설정, 내비게이션과 게시 정보 |
| `list_doc_pages` | `docs:read`, `admin:read` | O | 사이트 페이지 목록 |
| `get_doc_page` | `docs:read`, `admin:read` | O | 페이지 Markdown과 선택적 JSON |
| `list_doc_releases` | `docs:read`, `admin:read` | O | 게시 릴리스 목록 |
| `create_doc_site` | `docs:write`, `admin:write` | O | 문서 사이트 생성 |
| `update_doc_site` | `docs:write`, `admin:write` | O | 사이트 이름, 설정과 도메인 변경 |
| `delete_doc_site` | `docs:write`, `admin:write` | O | 확인 slug를 지정해 사이트 삭제 |
| `set_doc_navigation` | `docs:write`, `admin:write` | O | 탭·그룹·페이지 내비게이션 교체 |
| `create_doc_page` | `docs:write`, `admin:write` | O | Markdown 또는 JSON 페이지 생성 |
| `update_doc_page` | `docs:write`, `admin:write` | O | revision 기반 페이지 수정 |
| `delete_doc_page` | `docs:write`, `admin:write` | O | 페이지 삭제 |
| `publish_doc_site` | `docs:write`, `admin:write` | O | 새 불변 릴리스 게시 |
| `restore_doc_release` | `docs:write`, `admin:write` | O | 이전 릴리스 복원 |
문서 페이지의 `markdown`은 Mintlify 형식 MDX입니다. 먼저 `get_doc_authoring_guide`에서 지원 컴포넌트와 예제를 확인하세요. `get_doc_page`에는 `pageId`와 `path` 중 정확히 하나를 지정하고, 홈 페이지 경로는 빈 문자열(`""`)을 사용합니다. `update_doc_page`는 `baseRevision`으로 동시 수정 충돌을 감지합니다. 게시 취소는 관리 UI에서만 가능합니다.
현재 키로 어떤 도구를 쓸 수 있는지 모르겠다면 `get_api_key_info`를 먼저 호출하세요. 이 도구는 scope 없이도 호출할 수 있습니다.
## 프롬프트
`prompts/list`에서 다음 두 프롬프트를 조회하고 `prompts/get`으로 지침을 받을 수 있습니다. 프롬프트는 도구를 직접 실행하지 않습니다.
| 프롬프트 | 인자 | 안내하는 도구와 순서 |
| --- | --- | --- |
| `triage_todays_errors` | `propertyId` 필수 | 최근 24시간 `list_error_issues` → 상위 이슈의 `get_error_fix_context` → 사용자 확인 후에만 `update_error_issue_status` |
| `weekly_summary` | `projectSlug?` | 최근 7일 `list_projects` → `get_monitoring_snapshot` → `list_incidents` → `get_analytics_snapshot` → `list_error_issues` → `list_feedback` |
## 클라이언트 설정
아래 설정은 앱의 `조직 설정 → MCP 연결`(`//admin/mcp`) 화면에서도 복사 버튼과 함께 그대로 제공됩니다.
`.` 자리에는 발급받은 키를 넣으세요.
### opencode
`opencode.json`의 `mcp` 항목에 다음을 추가합니다.
```json
{
"mcp": {
"theseeker-crm": {
"type": "remote",
"url": "https://crm.theseeker.io/api/mcp",
"oauth": false,
"headers": {
"Authorization": "Bearer {file:~/.config/theseeker/crm-mcp-key}"
},
"enabled": true
}
}
}
```
opencode는 `{file:<경로>}`를 읽어 그 파일의 내용으로 치환하므로 설정 파일에 키를 평문으로 두지 않아도 됩니다.
`~/.config/theseeker/crm-mcp-key`에는 `.` 한 줄만 저장하고 권한을 `600`으로 두세요.
### Claude Code
```bash
claude mcp add --transport http theseeker-crm https://crm.theseeker.io/api/mcp --header "Authorization: Bearer ."
```
### Cursor
`~/.cursor/mcp.json` 또는 프로젝트의 `.cursor/mcp.json`에 다음을 추가합니다.
```json
{
"mcpServers": {
"theseeker-crm": {
"url": "https://crm.theseeker.io/api/mcp",
"headers": {
"Authorization": "Bearer ."
}
}
}
}
```
### curl
설정 없이 연결만 확인하려면 `initialize`와 `tools/list`를 직접 호출하세요.
```bash
curl -sS -X POST https://crm.theseeker.io/api/mcp \
-H "Authorization: Bearer ." \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
curl -sS -X POST https://crm.theseeker.io/api/mcp \
-H "Authorization: Bearer ." \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
```
## 오류와 Rate limit
전송 계층 오류는 HTTP status로 돌아옵니다.
| HTTP | 의미 |
| ---: | --- |
| 401 | 토큰 누락, 형식 오류, 폐기된 키 |
| 403 | IP allowlist 밖의 요청 |
| 405 | `POST` 외의 메서드 |
| 406 | `Content-Type` 또는 `Accept` 헤더 누락 |
| 429 | 요청 한도 초과 |
MCP endpoint는 키마다 분당 120회를 기본으로 허용합니다. 조직의 **API 키** 페이지에서 키별 한도를 분당 1~600회로 설정할 수 있습니다.
`429` 응답에는 `Retry-After`, `X-RateLimit-Limit`,
`X-RateLimit-Remaining` 헤더가 포함되며 `Retry-After`만큼 기다린 뒤 재시도하세요.
일일 도구 호출 예산은 UTC 날짜 기준으로 계산하며 `tools/call` 요청만 셉니다. 예산을 초과하면 HTTP `429`와
`{"error":{"code":"BUDGET_EXCEEDED",...}}` 본문을 반환하고, `Retry-After`는 다음 UTC 자정(00:00)까지 남은 초입니다.
거부된 호출은 사용량에 포함되지 않습니다. `get_api_key_info` 응답에는 유효 분당 한도(`rateLimitPerMinute`),
일일 예산(`dailyCallBudget`, `null`이면 무제한), 오늘 사용한 호출 수(`usedToday`)가 포함됩니다.
변경 작업 도구 그룹의 모든 결과는 성공·실패·거부 여부와 함께 감사 로그에 기록됩니다. scope, 프로젝트 범위,
일일 예산 때문에 거부된 도구 호출도 기록하며, `servers.logs` 호출 결과도 기록합니다. 사람의 UI 변경도 기록됩니다.
감사 로그는 `//admin/audit`에서 조직 관리자만 볼 수 있습니다.
도구 실행 중 발생한 오류는 HTTP `200`과 함께 MCP 결과의 `isError: true`로 돌아오고, 본문에 다음 JSON이 들어갑니다.
```json
{"error":{"code":"FORBIDDEN_SCOPE","message":"설명"}}
```
| Code | 의미 |
| --- | --- |
| `UNAUTHORIZED` | 인증 실패 |
| `FORBIDDEN_SCOPE` | 도구가 요구하는 scope 없음 |
| `FORBIDDEN_PROJECT` | 키 범위 밖의 프로젝트 지정 |
| `NOT_FOUND` | 대상 리소스 없음 |
| `VALIDATION` | 입력 검증 실패 |
| `CONFLICT` | slug 등 충돌 |
| `RATE_LIMITED` | 요청 한도 초과 |
| `UPSTREAM_ERROR` | 에이전트·게이트웨이가 요청을 처리하지 못함 |
| `INTERNAL` | 서버 내부 오류 |
REST API의 오류 규약은 [Errors와 Rate Limits](/api-reference/errors-and-rate-limits)를 참고하세요.